Lektionen des Moduls (2/2)
Pattern Matching, Option und Result
Rust besitzt einen extrem leistungsfähigen Ablaufsteuerungsmechanismus namens Pattern Matching (Musterabgleich). Er ermöglicht es, einen Wert mit einer Reihe von Mustern zu vergleichen und Code basierend auf dem übereinstimmenden Muster auszuführen.
Die match-Anweisung
Die match-Anweisung in Rust ähnelt dem switch in anderen Sprachen, ist aber viel leistungsfähiger und sicherer. Der Compiler garantiert, dass das Matching exhaustiv (vollständig) ist, was bedeutet, dass alle möglichen Fälle behandelt werden müssen:
enum Direction {
North,
South,
East,
West,
}
let dir = Direction::East;
match dir {
Direction::North => println!("Andiamo a Nord"),
Direction::South => println!("Andiamo a Sud"),
Direction::East => println!("Andiamo a Est"),
Direction::West => println!("Andiamo a Ovest"),
}
Umgang mit dem Fehlen von Werten: Option
Rust kennt kein Konzept für Nullwerte (null oder nil). Stattdessen definiert die Standardbibliothek ein Enum namens Option<T>, das Folgendes enthalten kann:
Some(T): Enthält einen Wert vom TypT.None: Zeigt das Fehlen eines Wertes an.
let x: Option<i32> = Some(5);
let y: Option<i32> = None;
match x {
Some(val) => println!("C'e un valore: {}", val),
None => println!("Nessun valore trovato"),
}
Umgang mit behebbaren Fehlern: Result
Für Operationen, die fehlschlagen können (wie das Lesen einer Datei oder das Konvertieren eines Strings in eine Zahl), verwendet Rust das Enum Result<T, E>, das zwei Varianten besitzt:
Ok(T): Die Operation war erfolgreich und enthält den ErfolgswertT.Err(E): Die Operation ist fehlgeschlagen und enthält den FehlerE.
fn divide(numerator: f64, denominator: f64) -> Result<f64, String> {
if denominator == 0.0 {
Err(String::from("Divisione per zero!"))
} else {
Ok(numerator / denominator)
}
}
Dank des Rust-Compilers sind Sie gezwungen, den Fall Err zu behandeln, bevor Sie auf den Wert in Ok zugreifen können. Dies verhindert viele Fehler zur Laufzeit.
Das Platzhalter-Muster _ (Wildcard)
Wenn wir mit Datentypen arbeiten, die eine große Anzahl von Varianten haben (wie Ganzzahlen), ist es unmöglich, alle Fälle in einem match aufzulisten. Rust ermöglicht die Verwendung des Platzhalters _, um alle verbleibenden Fälle abzufangen, die nicht explizit definiert sind:
let some_u8 = 3u8;
match some_u8 {
1 => println!("Uno"),
2 => println!("Due"),
_ => println!("Qualcos'altro"), // Gestisce tutti gli altri valori
}
Probiere es aus
Deklarieren Sie eine Variable maybe_value vom Typ Option<i32>, die Some(42) enthält. Verwenden Sie eine match-Anweisung auf maybe_value: Wenn sie Some(v) enthält, geben Sie 'value is: v' aus (mit println!), wenn sie None enthält, geben Sie 'no value' aus.
Hinweis anzeigen
Schreiben Sie einen Block `match maybe_value { Some(v) => println!('value is: {}', v), None => println!('no value') }`.
Lösung nach 3 Versuchen verfügbar
Vervollständigen Sie die Funktion check_age so, dass sie Ok('Adult') zurückgibt, wenn age größer oder gleich 18 ist, andernfalls Err('Minor').
Hinweis anzeigen
Verwenden Sie ein `if age >= 18`, um zu entscheiden, ob `Ok('Adult')`oder`Err('Minor')` zurückgegeben werden soll.
Lösung nach 3 Versuchen verfügbar
Deklarieren Sie ein Enum namens Status mit den Varianten Active und Inactive. Deklarieren Sie in der main-Methode eine Variable current_status mit dem Wert Status::Active. Verwenden Sie schließlich eine match-Anweisung auf current_status, um 'active' auszugeben, wenn der Status Active ist, oder 'inactive', wenn der Status Inactive ist.
Hinweis anzeigen
Definieren Sie das Enum vor der main-Methode mit `enum Status { Active, Inactive }`. Verwenden Sie in main `let current_status = Status::Active;`und führen Sie den`match` auf den Varianten aus.
Lösung nach 3 Versuchen verfügbar