if let und while let in Rust
Du hast match schon benutzt, um Option und Result zu behandeln. Meistens interessiert dich aber nur ein einziges Muster, und alles andere willst du ignorieren. Ein komplettes match mit einem _ => {}-Arm, der nichts tut, funktioniert zwar. Es ist aber mehr Aufwand, als die Situation verlangt. if let ist die Abkürzung dafür.
Das Problem mit einem vollständigen match
Abschnitt betitelt „Das Problem mit einem vollständigen match“fn main() { let age: Option<i32> = Some(30);
match age { Some(value) => println!("Das Alter ist {value}"), _ => {}, // dieser Fall interessiert uns eigentlich nicht }}Das _ => {} tut nichts, außer die Regel von match zu erfüllen, dass jeder Fall behandelt werden muss. Wenn du nur bei Some etwas tun willst, ist das mehr Code, als die Idee verdient.
fn main() { let age: Option<i32> = Some(30);
if let Some(value) = age { println!("Das Alter ist {value}"); }}Ausgabe:
Das Alter ist 30Lies es so: „Wenn age auf das Muster Some(value) passt, führe diesen Block aus – und value enthält den Wert, der darin steckte.“ Ist age gleich None, wird der Block einfach übersprungen. Kein Fehler, keine Ausgabe.
Ein else hinzufügen
Abschnitt betitelt „Ein else hinzufügen“if let kann ein else haben, genau wie ein normales if:
fn main() { let age: Option<i32> = None;
if let Some(value) = age { println!("Das Alter ist {value}"); } else { println!("Kein Alter angegeben"); }}if let mit Result
Abschnitt betitelt „if let mit Result“Mit Result, das du auf der Seite Result kennengelernt hast, funktioniert es genauso:
fn main() { let input = "42";
if let Ok(number) = input.parse::<i32>() { println!("Umgewandelt: {number}"); } else { println!("Das ließ sich nicht umwandeln"); }}Verketten mit else if let
Abschnitt betitelt „Verketten mit else if let“So wie es bei if ein else if gibt, kann auf if let ein else if let folgen. Rust probiert die Muster der Reihe nach aus und führt den ersten Block aus, der passt. Das ist praktisch, wenn du an mehreren Stellen nach einem Wert suchen kannst – in der Reihenfolge, die du bevorzugst:
fn main() { let nickname: Option<&str> = None; let full_name: Option<&str> = Some("Ferris Crab");
if let Some(nick) = nickname { println!("Hi, {nick}!"); } else if let Some(name) = full_name { println!("Hallo, {name}."); } else { println!("Hallo, Fremder."); }}Ausgabe:
Hallo, Ferris Crab.nickname ist None, also wird der erste Block übersprungen. full_name passt auf Some(name), also läuft dieser Block, und das letzte else wird nie erreicht. Du kannst auch eine ganz normale Bedingung einbauen, etwa else if is_admin { ... } – an jeder Stelle der Kette.
Jede Variable gibt es nur in ihrem eigenen Block: nick kannst du im zweiten Block nicht benutzen, und name nicht mehr nach dem Ende der Kette. Brauchst du den ausgepackten Wert für den ganzen restlichen Code, schau dir let-else auf der Seite Pattern Matching an.
while let
Abschnitt betitelt „while let“while let überträgt dieselbe Idee auf eine Schleife: Sie läuft so lange, wie ein Wert auf ein Muster passt. Besonders praktisch ist das, wenn du eine Collection Stück für Stück leeren willst:
fn main() { let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() { println!("{top}"); }}Ausgabe:
321.pop() liefert Some(wert), solange noch etwas übrig ist, und None, sobald der Vektor leer ist. In diesem Moment beendet while let die Schleife automatisch. Du musst die Länge nicht selbst prüfen.
if let oder match – was nimmst du wann?
Abschnitt betitelt „if let oder match – was nimmst du wann?“Nimm match, wenn du wirklich mehrere Fälle unterschiedlich behandeln musst. Greif zu if let, wenn dich nur ein einziges Muster interessiert und alles andere einfach ignoriert werden soll. if let ersetzt match nicht. Es ist nur eine kürzere Schreibweise für den häufigen Fall „Mich interessiert nur ein Arm“.
Übungen
Abschnitt betitelt „Übungen“1. Einen Stapel aufsummieren
Abschnitt betitelt „1. Einen Stapel aufsummieren“Starte mit let mut numbers = vec![4, 8, 15]; und einer laufenden Summe total von 0. Nimm mit while let und .pop() eine Zahl nach der anderen vom Ende, addiere sie jeweils zu total und gib die Zahl und die neue Summe aus. Tipp: total braucht mut, und total += n addiert etwas dazu.
Lösung anzeigen
fn main() { let mut numbers = vec![4, 8, 15]; let mut total = 0;
while let Some(n) = numbers.pop() { total += n; println!("{n} genommen, Summe ist jetzt {total}"); }}Ausgabe:
15 genommen, Summe ist jetzt 158 genommen, Summe ist jetzt 234 genommen, Summe ist jetzt 27.pop() nimmt vom Ende – deshalb kommt die 15 zuerst heraus.
2. Ein Alter aus Text prüfen
Abschnitt betitelt „2. Ein Alter aus Text prüfen“Speichere let input = "17";. Lässt es sich als u32 umwandeln, gib aus, ob das Alter volljährig (18 oder älter) oder minderjährig ist. Klappt die Umwandlung nicht, gib aus, dass es keine Zahl ist. Probier auch einmal input mit "abc" aus. Tipp: Schreib ein normales if / else in den if let-Block.
Lösung anzeigen
fn main() { let input = "17";
if let Ok(age) = input.parse::<u32>() { if age >= 18 { println!("{age} ist volljährig"); } else { println!("{age} ist minderjährig"); } } else { println!("'{input}' ist keine Zahl"); }}Ausgabe:
17 ist minderjährigMit input = "abc" schlägt die Umwandlung fehl, das äußere else läuft, und es wird 'abc' ist keine Zahl ausgegeben.
Zusammenfassung
Abschnitt betitelt „Zusammenfassung“if let Muster = wert { ... }führt den Block nur aus, wennwertaufMusterpasst – alles andere wird still übersprungen.- Mit
elsebehandelst du den Fall, in dem das Muster nicht passt, genau wie bei einem normalenif. Mitelse if letverkettest du mehrere Muster. while let Muster = wert { ... }wiederholt die Schleife, solange der Wert passt. Das ist praktisch, um eine Collection mit.pop()zu leeren.- Nimm
if let/while let, wenn dich nur ein Muster interessiert, undmatch, wenn du mehrere Fälle getrennt behandeln musst.
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. Was passiert, wenn if let Some(value) = age ausgeführt wird und age gleich None ist?
2. Wann solltest du match statt if let verwenden?
3. Wann endet die Schleife while let Some(top) = stack.pop() { ... }?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- Prägnanter Kontrollfluss mit if let und let…else – Das Rust-Buch: die offizielle Einführung, die auch let-else behandelt.
- if let – Rust by Example (auf Englisch): ausführbare Beispiele mit
Optionund eigenen Enums – und warumif letbei nur einem Muster besser ist alsmatch. - while let – Rust by Example (auf Englisch): eine Schleife aus
loop+match, umgeschrieben in ein kürzereswhile let. if let-Muster – The Rust Reference (auf Englisch): die genauen Regeln, auch dazu, wieif letmitmatchzusammenhängt.