Zum Inhalt springen

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.

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.

fn main() {
let has_value: Option<i32> = Some(5);
let no_value: Option<i32> = None;
println!("{:?}", has_value);
println!("{:?}", no_value);
}

Ausgabe:

Some(5)
None
▶ Selbst ausprobieren

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"),
}
}
▶ Selbst ausprobieren
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: Alice
Benutzer nicht gefunden
▶ Selbst ausprobieren

Die 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.

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}");
}
▶ Selbst ausprobieren

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

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: 8
Mit Ersatzwert: 0
▶ Selbst ausprobieren

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 = 80
brightness ist nicht gesetzt
▶ Selbst ausprobieren

Die Schlüssel "volume" (Lautstärke) und "brightness" (Helligkeit) bleiben auf Englisch, so wie Namen von Einstellungen in Konfigurationsdateien meistens aussehen.

  • Option<T> steht für einen Wert, der da sein kann oder auch nicht – Rust hat kein null.
  • Some(value) enthält etwas; None bedeutet, dass nichts da ist.
  • match ist der sichere Weg, beide Fälle zu behandeln. Der Compiler lässt dich keinen vergessen.
  • .unwrap_or(default) liefert einen Ersatzwert; .unwrap() löst bei None eine Panic aus – setz es sparsam ein.

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