Matching von Datenvarianten
Teil des Abschnitts Object Oriented Programming der Rust-Journey von Coddy — Lektion 16 von 61.
In der vorherigen Lektion haben Sie match innerhalb von Enum-Methoden verwendet, um verschiedene Varianten zu behandeln. Konzentrieren wir uns nun darauf, wie match tatsächlich die in diesen Varianten gespeicherten Daten extrahiert – eine Technik, die als Destrukturierung bezeichnet wird.
Wenn du einen Abgleich auf eine Enum-Variante durchführst, 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 Zweig extrahiert Daten unterschiedlich, basierend auf der Struktur der Variante. Für strukturähnliche Varianten verwenden Sie { field_name }, um benannte Felder zu extrahieren. Für Tupel-Varianten verwenden Sie Positionsvariablen wie (width, height).
Die von Ihnen gewählten Variablennamen werden innerhalb dieses Match-Arms verfügbar. Dies ist leistungsstark, da Sie gleichzeitig prüfen, welche Variante Sie haben, und Zugriff auf deren Payload erhalten.
Der Compiler stellt sicher, dass Sie jede Variante behandeln, und die extrahierten Werte sind sofort einsatzbereit – keine zusätzlichen Schritte erforderlich.
Aufgabe
EinfachLassen Sie uns einen Befehlsprozessor erstellen, der verschiedene Arten von Benutzerbefehlen verarbeitet. Jeder Befehl enthält unterschiedliche Daten, und Ihr Prozessor wird Pattern Matching verwenden, um diese Daten zu extrahieren und entsprechende Antworten zu erzeugen.
Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:
command.rs: Definieren Sie ein öffentlichesCommand-Enum 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: Binden Sie Ihr Befehlsmodul ein, erstellen Sie eine Instanz jeder Befehlsvariante unter Verwendung der bereitgestellten Eingaben und rufen Sie dieexecute-Methode für jede auf, um die Ergebnisse auszugeben.
Ihre execute-Methode sollte jede Variante destrukturieren, um auf ihre Daten zuzugreifen, und Nachrichten in genau diesen Formaten zurückgeben:
- Für
Say:Saying: {message} - Für
Move:Moving {steps} steps {direction} - Für
Calculate:{a} + {b} = {sum}
Ihre Ausgabe sollte das Ergebnis jedes Befehls in einer eigenen Zeile anzeigen:
Saying: {message}
Moving {steps} steps {direction}
{a} + {b} = {sum}Zum Beispiel, mit einer Say-Nachricht von "Hello world", einer Bewegung von 5 Schritten nach "north" und einer Berechnung von 10 und 25, wäre die Ausgabe:
Saying: Hello world
Moving 5 steps north
10 + 25 = 35Sie erhalten fünf Eingaben: die Say-Nachricht, die Richtung, die Anzahl der Schritte und die zwei zu berechnenden Zahlen.
Spickzettel
Pattern Matching mit match ermöglicht es Ihnen, Enum-Varianten zu destrukturieren und deren Daten direkt im Pattern zu extrahieren.
Für Tupel-Varianten verwenden Sie Positionsvariablen:
enum Event {
KeyPress(char),
Resize(u32, u32),
}
match event {
Event::KeyPress(key) => {
println!("Key: {}", key);
}
Event::Resize(width, height) => {
println!("{}x{}", width, height);
}
}Für Struct-ähnliche Varianten verwenden Sie die Syntax für benannte Felder:
enum Event {
Click { x: i32, y: i32 },
}
match event {
Event::Click { x, y } => {
println!("Clicked at ({}, {})", x, y);
}
}Die extrahierten Variablen werden innerhalb ihres jeweiligen Match-Arms verfügbar, sodass Sie gleichzeitig den Variantentyp prüfen und auf seine Daten zugreifen können.
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 unter Verwendung von say_message und führe ihn aus
// TODO: Erstelle einen Move-Befehl unter Verwendung von direction und steps und führe ihn aus
// TODO: Erstelle einen Calculate-Befehl unter Verwendung von 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 Object Oriented Programming
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