Rust basiert auf expliziter Fehlerbehandlung: Ausnahmen fehlen, stattdessen wird der Rückgabewert Result<T, E> verwendet. Dies gewährleistet Sicherheit und Vorhersagbarkeit des Codes.
Hintergrund:
Viele Sprachen haben den Weg der Ausnahmen eingeschlagen, was zu unerwarteten Situationen und der Notwendigkeit führt, Ausnahmen zur Laufzeit explizit zu behandeln. Rust hat von Anfang an auf Typkontrolle gesetzt, alle Fehler müssen Teil der Funktionssignatur sein.
Problem:
Die Hauptaufgabe besteht darin, Code zu schreiben, in dem Fehler nicht ignoriert oder maskiert werden, es gibt keine "abstürzenden" Funktionen, aber der Code bleibt kompakt und lesbar. Fehler müssen korrekt nach oben propagiert werden, ohne Informationen über ihren Typ zu verlieren und die Logik nicht zu verwirren.
Lösung:
Das Schlüsselwerkzeug ist der Typ Result<T, E> und der Operator ?, der das Ergebnis automatisch "entpackt": Im Fehlerfall erfolgt ein sofortiger Ausstieg aus der Funktion mit Rückgabe des Fehlers, bei Erfolg wird der Wert zurückgegeben.
Beispielcode:
fn read_number(file: &str) -> Result<i32, std::io::Error> { let content = std::fs::read_to_string(file)?; let num: i32 = content.trim().parse()?; Ok(num) }
Wesentliche Merkmale:
.map_err() und andere Methoden)Kann man ? in Funktionen verwenden, die Unit (void) zurückgeben?
Nein, der Operator ? ist nur innerhalb von Funktionen zulässig, die Result oder Option zurückgeben. Wenn eine Funktion () zurückgibt, kann ? nicht verwendet werden.
Was passiert, wenn die Fehlertypen in mehreren Aufrufen mit ? unterschiedlich sind?
Es tritt ein Kompilierungsfehler auf: Der Fehlertyp muss eindeutig definiert sein. Man muss entweder alle Fehler auf einen gemeinsamen Typ über .map_err() bringen oder thiserror verwenden oder eine Enum-Hülle auf API-Ebene beschreiben. Beispiel:
fn foo() -> Result<_, MyError> { let a = bar()?; let b = baz().map_err(MyError::Baz)?; Ok(…) }
Warum ist .unwrap() in der internen Logik gefährlich?
Es gibt weit verbreitete falsche Meinungen, dass man in "hauptsächlichem" Code unwrap() bedenkenlos verwenden kann, "es wird schon nicht abstürzen". In der Praxis führt auch ein kleiner unsichtbarer Fehler zu einem Panic zur Laufzeit — die Sicherheit des Programms ist gefährdet.
unwrap/expect, insbesondere in der internen LogikIm Produktionscode wurden viele unwrap() nach einer schnellen Fehlersuche zurückgelassen. Infolgedessen stürzte die Anwendung bei jedem Parsing-Fehler aufgrund ungültiger Benutzereingaben ab.
Vorteile:
Nachteile:
Es wurde ein vollständiger Stack von Result<T, E> mit expliziter Beschreibung der Fehler verwendet und nur ? und .map_err() angewendet, wobei alle Informationen über den Fehler erhalten blieben.
Vorteile:
Nachteile: