In Rust können Enumerationen (Enums) nicht nur Werte (Varianten) speichern, sondern auch zugehörige Daten (Payload). Das macht sie besonders nützlich zur Erstellung algebraischer Datentypen, zum Beispiel zur Darstellung von Zuständen oder Nachrichten mit Parametern. Zum Beispiel:
enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), }
Zur Verarbeitung solcher Enums verwendet man normalerweise den match-Operator, der es ermöglicht, die verschachtelten Werte jeder Variante zu entpacken:
let msg = Message::Move { x: 10, y: 20 }; match msg { Message::Quit => println!("Quit message"), Message::Move { x, y } => println!("Move to ({}, {})", x, y), Message::Write(text) => println!("Text: {}", text), Message::ChangeColor(r, g, b) => println!("Change color to ({}, {}, {})", r, g, b), }
Dieser Ansatz ermöglicht eine sichere und explizite Verarbeitung aller möglichen Fälle, was Fehler in der Programmlogik minimiert.
Warum gibt es in Rust kein null für Enums und was wird zurückgegeben, wenn man versucht, mit einer nicht existierenden Variante abzugleichen?
Eine häufige falsche Antwort: "Der Compiler überspringt den Fehler, wenn man nicht alle Varianten des Enums im Match behandelt."
Tatsächlich gibt der Compiler einen Fehler aus, wenn nicht alle möglichen Varianten berücksichtigt oder verlangt, einen Catch-All (_) hinzuzufügen. Zum Beispiel:
enum Status { Ok, Err(String) } let st = Status::Ok; match st { Status::Ok => println!("Ok"), // Wenn man Status::Err vergisst, wird der Compiler sich beschweren }
Geschichte In einem Projekt wurde bei der Erweiterung des Enums die Verarbeitung der neuen Variante im Match an allen Stellen, an denen es verwendet wurde, nicht hinzugefügt. Dies führte zu einem panic! im Release, da das
matchnicht erschöpfend (exhaustive) war und die Tests nicht alle Fälle abdeckten.
Geschichte In einem anderen Fall versuchten sie, Enum mit einfachem
==zu vergleichen, ohne PartialEq für komplexe Varianten mit zugehörigen Daten zu implementieren, was zu einem unerwarteten Kompilierungsfehler führte.
Geschichte Das Team verwendete Catch-All (
_), um Varianten zu verarbeiten, und später, bei der Hinzufügung neuer Varianten, führte dies dazu, dass die Logik neue Fälle stillschweigend ignorierte, was zu schwer zu findenden Defekten führte.