Matching von Datenvarianten
Teil des Abschnitts Objektorientierte Programmierung der Rust-Journey von Coddy. Lektion 16 von 61.
In der vorherigen Lektion hast du match innerhalb von Enum-Methoden verwendet, um verschiedene Varianten zu behandeln. Nun konzentrieren wir uns darauf, wie match tatsächlich die in diesen Varianten gespeicherten Daten extrahiert: eine Technik namens Destrukturierung.
Wenn du eine Enum-Variante abgleichst, die Daten enthält, kannst du diese Daten direkt im Muster an Variablen binden:
enum Event {
Click { x: i32, y: i32 },
KeyPress(char),
Resize(u32, u32),
}
fn handle_event(event: Event) {
match event {
Event::Click { x, y } => {
println!("Clicked at ({}, {})", x, y);
}
Event::KeyPress(key) => {
println!("Key pressed: {}", key);
}
Event::Resize(width, height) => {
println!("Resized to {}x{}", width, height);
}
}
}
Jeder Arm extrahiert Daten unterschiedlich, abhängig von der Struktur der Variante. Für struct-ähnliche Varianten verwendest du { field_name }, um benannte Felder herauszuziehen. Für Tupelvarianten verwendest du Positionsvariablen wie (width, height).
Die Variablennamen, die du auswählst, werden innerhalb dieses match-Zweigs verfügbar. Das ist besonders praktisch, weil du gleichzeitig überprüfst, welche Variante vorliegt, und Zugriff auf deren Nutzlast erhältst.
Der Compiler stellt sicher, dass du jede Variante behandelst, und die extrahierten Werte sind sofort einsatzbereit: keine zusätzlichen Schritte erforderlich.
Aufgabe
EinfachWir erstellen einen Befehlsprozessor, der verschiedene Arten von Benutzerbefehlen verarbeitet. Jeder Befehl enthält unterschiedliche Daten, und dein Prozessor verwendet Pattern Matching, um diese Daten zu extrahieren und geeignete Antworten zu erzeugen.
Du erstellst zwei Dateien, um deinen Code zu organisieren:
command.rs: Definiere eine öffentlicheCommand-Enumeration mit drei Varianten:Say: enthält eine einzelneString-Nachricht (Tupel-Syntax)Move: enthält benannte Felder:direction(String) undsteps(u32)Calculate: enthält zweii32-Werte, die zu addierende Zahlen darstellen (Tupel-Syntax)
execute-Methode, diematchverwendet, um jede Variante zu destrukturieren und einenStringzurückzugeben, der die ausgeführte Aktion beschreibt.main.rs: Binde dein command-Modul ein, erstelle mithilfe der vorgegebenen Eingaben eine Instanz jeder Befehlsvariante und rufe für jede dieexecute-Methode auf, um die Ergebnisse auszugeben.
Deine execute-Methode sollte jede Variante destrukturieren, um auf ihre Daten zuzugreifen, und Nachrichten in diesen exakten Formaten zurückgeben:
- Für
Say:Saying: {message} - Für
Move:Moving {steps} steps {direction} - Für
Calculate:{a} + {b} = {sum}
Deine Ausgabe sollte das Ergebnis jedes Befehls in einer eigenen Zeile anzeigen:
Saying: {message}
Moving {steps} steps {direction}
{a} + {b} = {sum}Wenn die Say-Nachricht beispielsweise "Hello world" lautet, eine Bewegung aus 5 Schritten in "north"-Richtung besteht und die Berechnung mit 10 und 25 durchgeführt wird, würde die Ausgabe folgendermaßen aussehen:
Saying: Hello world
Moving 5 steps north
10 + 25 = 35Du erhältst fünf Eingaben: die Say-Nachricht, die Richtung, die Anzahl der Schritte und die beiden zu berechnenden Zahlen.
Probier es selbst
mod command;
use command::Command;
fn main() {
// Eingaben lesen
let mut say_message = String::new();
std::io::stdin().read_line(&mut say_message).expect("Failed to read line");
let say_message = say_message.trim().to_string();
let mut direction = String::new();
std::io::stdin().read_line(&mut direction).expect("Failed to read line");
let direction = direction.trim().to_string();
let mut steps_input = String::new();
std::io::stdin().read_line(&mut steps_input).expect("Failed to read line");
let steps: u32 = steps_input.trim().parse().expect("Failed to parse steps");
let mut num1_input = String::new();
std::io::stdin().read_line(&mut num1_input).expect("Failed to read line");
let num1: i32 = num1_input.trim().parse().expect("Failed to parse num1");
let mut num2_input = String::new();
std::io::stdin().read_line(&mut num2_input).expect("Failed to read line");
let num2: i32 = num2_input.trim().parse().expect("Failed to parse num2");
// TODO: Erstelle einen Say-Befehl mit say_message und führe ihn aus
// TODO: Erstelle einen Move-Befehl mit direction und steps und führe ihn aus
// TODO: Erstelle einen Calculate-Befehl mit num1 und num2 und führe ihn aus
// TODO: Gib die Ergebnisse jeder Befehlsausführung aus
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Methoden und Verhalten
Einführung in ImplementierungsblöckeDer Self-ParameterVeränderliche MethodenAssoziierte FunktionenMehrere ImplementierungsblöckeMethod ChainingRückblick – Rechteck-Aktionen4Projekt: Virtuelles Haustier
Das Haustier definierenDas Haustier füttern7Standard-Traits
Das Debug-TraitDas Display-TraitClone und CopyGleichheits-TraitsZusammenfassung – Druckbarer Punkt10Projekt: Dokumentensystem
Das Draw-TraitText-Komponente2Kapselung und Module
Grundlagen der ModuleDas Public-SchlüsselwortPrivate FelderGetterSetterWiederholung – Sicherer Tresor5Generics
Generische StructsGenerische MethodenMehrere generische TypenGenerische FunktionenZusammenfassung - Koordinatenpunkt8Traits als Einschränkungen
Syntax für Trait BoundsMehrfache BoundsDie Where-KlauselTypen mit Traits zurückgebenRückblick – Generischer Drucker11Design Patterns in Rust
Newtype-PatternKompositionDas Drop-TraitFrom und IntoZusammenfassung – Smart Pointer Mock3Fortgeschrittene Enums
Enums mit DatenMethoden für EnumsMatching von DatenvariantenDas Option-Enum erneut betrachtetZusammenfassung – Shape-Enum6Definition von Traits
Was ist ein Trait?Traits implementierenStandardimplementierungenStandardimplementierungen überschreibenTraits mit ParameternZusammenfassung – Media PlayerÜbe selbstständig: Online-Rust-Compiler