Einleitung: Warum Rust kein try/catch verwendet?
In den meisten Programmiersprachen (JavaScript, Python, Java) basiert die Fehlerbehandlung auf dem Ausnahmemechanismus und der try/catch-Konstruktion. In Rust fehlt ein solcher Ansatz jedoch. Stattdessen verwenden Entwickler ein mächtiges Typsystem, das Fehler zu einem Teil der Funktionssignatur macht. Dies ist kein Zufall, sondern eine durchdachte architektonische Entscheidung: Rust strebt nach Vorhersagbarkeit und Sicherheit zur Kompilierzeit und schließt versteckte Programmabstürze aus.
In diesem Artikel behandeln wir:
- Warum Rust auf
try/catchverzichtet hat; - Wie die wichtigsten Werkzeuge funktionieren:
Option,Result,unwrap(),expect(); - Was der
?-Operator (Fragezeichen) ist; - Wann man
panic!und das Makrotry!(veraltet) verwendet; - Moderne Praktiken der Fehlerbehandlung in Rust 2024.
1. Grundlagen: Option und Result – die zwei Haupttypen
Typ Option: Wenn ein Wert fehlen kann
Option<T> ist eine Aufzählung (enum), die entweder einen Wert (Some(T)) oder dessen Fehlen (None) darstellt. Er eignet sich ideal für Situationen, in denen im klassischen Sinne kein Fehler auftritt, das Ergebnis aber leer sein kann.
fn find_user(id: u32) -> Option<String> { let database = vec!["Alice".to_string(), "Bob".to_string()]; if id < database.len() { Some(database[id].clone()) } else { None }}
fn main() { match find_user(1) { Some(name) => println!("Gefunden: {}", name), None => println!("Benutzer nicht gefunden"), }}Typ Result: Erfolg oder Fehler
Result<T, E> ist das Hauptwerkzeug zur Fehlerbehandlung. Es ist ebenfalls ein enum: Ok(T) (Erfolg) oder Err(E) (Fehler).
use std::fs::File;use std::io::Read;
fn read_file(path: &str) -> Result<String, std::io::Error> { let mut file = File::open(path)?; let mut content = String::new(); file.read_to_string(&mut content)?; Ok(content)}2. Der ?-Operator (Fragezeichen) – Ersatz für try/catch
Der ?-Operator ist die wichtigste Methode, um Fehler in Rust nach oben zu reichen. Er ersetzt umständliche match-Konstruktionen und macht den Code sauber. Ist das Ergebnis Ok, wird der Wert extrahiert und der Variablen zugewiesen. Ist es Err, gibt die Funktion diesen Fehler sofort zurück.
use std::fs;use std::io;
fn copy_file(source: &str, destination: &str) -> io::Result<()> { let data = fs::read(source)?; // bei Fehler — Ausstieg fs::write(destination, &data)?; // bei Fehler — Ausstieg Ok(())}
fn main() -> io::Result<()> { copy_file("source.txt", "dest.txt")?; println!("Datei erfolgreich kopiert"); Ok(())}Wichtig: Der ?-Operator funktioniert nur in Funktionen, die Result, Option oder Typen zurückgeben, die das FromResidual-Merkmal implementieren.
3. panic!, unwrap und expect – Wenn der Fehler fatal ist
Das Makro panic!
panic!() löst einen Programmabbruch aus (stack unwinding). Es wird nur in Situationen verwendet, in denen die weitere Ausführung unmöglich oder sinnlos ist: Logikfehler im Programm, Verletzung von Invarianten, Tests.
fn division(a: i32, b: i32) -> i32 { if b == 0 { panic!("Division durch Null!"); } a / b}Die Methoden unwrap() und expect()
unwrap() ist eine schnelle Möglichkeit, einen Wert aus Option oder Result zu extrahieren. Wenn sich darin None oder Err befindet – wird