Option in Rust
Rust kennt kein null. Wenn ein Wert fehlen kann, steht das direkt im Typ – mit Option. Am Anfang wirkt das etwas umständlich. Dafür verschwindet eine ganze Fehlerklasse: die „Null-Referenz“, die in anderen Sprachen unzählige Abstürze verursacht hat.
So sieht Option aus
Abschnitt betitelt „So sieht Option aus“Option ist ein Enum mit zwei Varianten:
enum Option<T> { Some(T), // ein Wert ist vorhanden None, // kein Wert}Eigentlich kennst du das schon: .get() bei einem Vektor und .get() bei einer HashMap geben beide eine Option zurück.
Eine Option erzeugen
Abschnitt betitelt „Eine Option erzeugen“fn main() { let has_value: Option<i32> = Some(5); let no_value: Option<i32> = None;
println!("{:?}", has_value); println!("{:?}", no_value);}Ausgabe:
Some(5)NoneEine Option mit match behandeln
Abschnitt betitelt „Eine Option mit match behandeln“Der sichere Weg, an den Wert zu kommen, ist match. Rust zwingt dich, beide Fälle zu behandeln. So kannst du den Fall „Wert fehlt“ nicht versehentlich vergessen:
fn main() { let age: Option<i32> = Some(30);
match age { Some(value) => println!("Das Alter ist {value}"), None => println!("Kein Alter angegeben"), }}Ein Beispiel aus der Praxis
Abschnitt betitelt „Ein Beispiel aus der Praxis“fn find_user(id: u32) -> Option<&'static str> { if id == 1 { Some("Alice") } else { None }}
fn main() { match find_user(1) { Some(name) => println!("Gefunden: {name}"), None => println!("Benutzer nicht gefunden"), }
match find_user(99) { Some(name) => println!("Gefunden: {name}"), None => println!("Benutzer nicht gefunden"), }}Ausgabe:
Gefunden: AliceBenutzer nicht gefundenDie Funktion gibt kein null zurück und wirft auch keine Ausnahme, wenn sie niemanden findet. Stattdessen sagt schon ihr Rückgabetyp jedem Aufrufer: „Vielleicht finde ich nichts.“ Und der Compiler lässt nicht zu, dass jemand diese Möglichkeit ignoriert.
Abkürzungen: unwrap_or und unwrap
Abschnitt betitelt „Abkürzungen: unwrap_or und unwrap“In einfachen Fällen wirkt ein komplettes match schnell übertrieben. Dafür gibt es ein paar Abkürzungen:
fn main() { let age: Option<i32> = None;
let value = age.unwrap_or(0); // 0 als Ersatz, wenn kein Wert da ist println!("{value}");}Außerdem gibt es .unwrap(). Das liefert dir den Wert direkt – löst aber eine Panic aus (das Programm stürzt ab), wenn er None ist:
let age: Option<i32> = Some(30);let value = age.unwrap(); // hier kein Problem, denn age ist SomeÜbungen
Abschnitt betitelt „Übungen“1. Die erste gerade Zahl
Abschnitt betitelt „1. Die erste gerade Zahl“Schreib fn first_even(numbers: &[i32]) -> Option<i32>. Die Funktion gibt die erste gerade Zahl im Slice zurück, oder None, wenn es keine gibt. Gib das Ergebnis für [3, 7, 8, 10] mit match aus und für [1, 3, 5] mit .unwrap_or(0). Tipp: Lauf durch den Slice und gib return Some(n) zurück, sobald n % 2 == 0 gilt. Nach der Schleife gibst du None zurück.
Lösung anzeigen
fn first_even(numbers: &[i32]) -> Option<i32> { for &n in numbers { if n % 2 == 0 { return Some(n); } } None}
fn main() { match first_even(&[3, 7, 8, 10]) { Some(n) => println!("Erste gerade Zahl: {n}"), None => println!("Keine geraden Zahlen"), }
let fallback = first_even(&[1, 3, 5]).unwrap_or(0); println!("Mit Ersatzwert: {fallback}");}Ausgabe:
Erste gerade Zahl: 8Mit Ersatzwert: 02. Eine Einstellung nachschlagen
Abschnitt betitelt „2. Eine Einstellung nachschlagen“Leg eine HashMap mit Einstellungen an, die nur "volume" mit dem Wert 80 enthält. Lauf dann über die Schlüssel "volume" und "brightness" und gib den Wert aus, wenn es ihn gibt, sonst eine Meldung „nicht gesetzt“. Tipp: .get(key) bei einer HashMap gibt eine Option zurück. Darauf kannst du direkt mit match reagieren.
Lösung anzeigen
use std::collections::HashMap;
fn main() { let mut settings = HashMap::new(); settings.insert("volume", 80);
for key in ["volume", "brightness"] { match settings.get(key) { Some(value) => println!("{key} = {value}"), None => println!("{key} ist nicht gesetzt"), } }}Ausgabe:
volume = 80brightness ist nicht gesetztDie Schlüssel "volume" (Lautstärke) und "brightness" (Helligkeit) bleiben auf Englisch, so wie Namen von Einstellungen in Konfigurationsdateien meistens aussehen.
Zusammenfassung
Abschnitt betitelt „Zusammenfassung“Option<T>steht für einen Wert, der da sein kann oder auch nicht – Rust hat keinnull.Some(value)enthält etwas;Nonebedeutet, dass nichts da ist.matchist der sichere Weg, beide Fälle zu behandeln. Der Compiler lässt dich keinen vergessen..unwrap_or(default)liefert einen Ersatzwert;.unwrap()löst beiNoneeine Panic aus – setz es sparsam ein.
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. Was benutzt Rust statt null für einen Wert, der fehlen kann?
2. Was passiert, wenn du .unwrap() auf einem None-Wert aufrufst?
3. Was macht age.unwrap_or(0), wenn age None ist?
4. Warum gilt match als sicherer Weg, um an den Wert in einer Option zu kommen?
5. Welche der auf dieser Seite erwähnten Methoden geben bereits eine Option zurück?
Punkte: 0 / 5
Weiterlesen
Abschnitt betitelt „Weiterlesen“- Die Aufzählung Option – Das Rust-Buch: die offizielle Erklärung, warum Rust
Optionstattnullverwendet. std::option– Doku der Standardbibliothek (auf Englisch): ein Überblick über alles, was du mit einerOptionmachen kannst, mit praktischen Methoden wiemap,and_thenundis_some.- Option & unwrap – Rust by Example (auf Englisch): kurze, ausführbare Beispiele zu
match,unwrapund dazu, wann eine Panic passiert. Option<T>– Doku der Standardbibliothek (auf Englisch): die vollständige Liste der Methoden, jede mit einem kleinen Beispiel zum Kopieren.