Enums mit Daten
Teil des Abschnitts Object Oriented Programming der Rust-Journey von Coddy — Lektion 14 von 61.
Basis-Enums in Rust ermöglichen es Ihnen, einen Typ mit einer festen Menge an Varianten zu definieren—wie Direction::North oder Status::Active. Aber Rust-Enums sind weitaus mächtiger als das. Jede Variante kann ihre eigenen Daten enthalten, was Enums unglaublich flexibel für die Modellierung von realen Szenarien macht.
Stellen Sie sich ein Messaging-System vor, bei dem verschiedene Nachrichtentypen unterschiedliche Informationen enthalten. Eine Textnachricht hat einen Inhalt, ein Verschiebungsbefehl hat Koordinaten und ein Beendigungssignal hat gar nichts. In Rust können Sie all dies mit einem einzigen Enum darstellen:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}
Jede Variante hat eine andere Form. Quit enthält keine Daten – es ist nur ein Signal.
Move verwendet eine Struct-ähnliche Syntax mit benannten Feldern. Write enthält einen einzelnen String unter Verwendung der Tupel-Syntax. ChangeColor enthält drei Werte, die RGB-Komponenten darstellen.
Das Erstellen von Instanzen dieser Varianten sieht so aus:
let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
let m3 = Message::Write(String::from("Hello"));
let m4 = Message::ChangeColor(255, 128, 0);
Das Schöne an diesem Ansatz ist, dass m1, m2, m3 und m4 alle vom gleichen Typ sind: Message. Sie können sie in derselben Sammlung speichern, sie an dieselbe Funktion übergeben oder jede beliebige Variante von einer einzelnen Funktion zurückgeben. Das Enum vereinheitlicht verschiedene Datenformen unter einem Typ, während die spezifischen Informationen, die jede Variante benötigt, erhalten bleiben.
Aufgabe
EinfachLassen Sie uns ein Benachrichtigungssystem bauen, das Enums mit Daten verwendet, um verschiedene Arten von Alarmen darzustellen. Jeder Benachrichtigungstyp trägt unterschiedliche Informationen — einige haben Nachrichten, einige haben numerische Werte und einige sind einfache Signale.
Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:
notification.rs: Definieren Sie ein öffentlichesNotificationEnum mit drei Varianten:Alert— enthält eine einzelneStringNachricht (Tupel-Syntax)Reminder— enthält benannte Felder:title(String) undminutes(u32)Dismiss— enthält keine Daten, nur ein Signal
main.rs: Binden Sie Ihr Benachrichtigungsmodul ein und erstellen Sie eine Instanz jeder Variante. Geben Sie dann Informationen über jede Benachrichtigung aus, um zu demonstrieren, dass alle drei Varianten vom gleichen Typ sind, aber unterschiedliche Daten tragen.
Verwenden Sie beim Drucken die Debug-Formatierung ({:?}), um jede Benachrichtigung anzuzeigen. Sie müssen das Debug-Trait für Ihr Enum ableiten (derive), damit es auf diese Weise gedruckt werden kann.
Ihre Ausgabe sollte alle drei Benachrichtigungen zeigen, jede in einer eigenen Zeile:
Alert("{message}")
Reminder { title: "{title}", minutes: {minutes} }
DismissZum Beispiel, mit einer Alert-Nachricht "Server down", einem Reminder mit dem Titel "Meeting" und 30 Minuten, wäre die Ausgabe:
Alert("Server down")
Reminder { title: "Meeting", minutes: 30 }
DismissSie erhalten drei Eingaben: die Alert-Nachricht, den Reminder-Titel und die Reminder-Minuten.
Spickzettel
Enum-Varianten in Rust können verschiedene Datentypen enthalten, was sie zu einem mächtigen Werkzeug für die Modellierung unterschiedlicher Szenarien unter einem einzigen Typ macht.
Enums mit Daten definieren
Jede Variante kann ihre eigene Datenstruktur haben:
enum Message {
Quit, // Keine Daten
Move { x: i32, y: i32 }, // Benannte Felder (Struct-ähnlich)
Write(String), // Einzelner Wert (Tupel-Syntax)
ChangeColor(u8, u8, u8), // Mehrere Werte (Tupel-Syntax)
}
Enum-Instanzen erstellen
let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
let m3 = Message::Write(String::from("Hello"));
let m4 = Message::ChangeColor(255, 128, 0);
Alle Instanzen haben denselben Typ (Message), obwohl sie unterschiedliche Daten enthalten. Dies ermöglicht es, sie einheitlich in Sammlungen zu speichern, an Funktionen zu übergeben oder von Funktionen zurückzugeben.
Debug-Trait
Um Enums mit der Formatierung {:?} auszugeben, leiten Sie den Debug-Trait ab:
#[derive(Debug)]
enum Message {
// Varianten...
}
Probier es selbst
mod notification;
use notification::Notification;
fn main() {
// Eingaben lesen
let mut alert_message = String::new();
std::io::stdin().read_line(&mut alert_message).expect("Failed to read line");
let alert_message = alert_message.trim().to_string();
let mut reminder_title = String::new();
std::io::stdin().read_line(&mut reminder_title).expect("Failed to read line");
let reminder_title = reminder_title.trim().to_string();
let mut minutes_input = String::new();
std::io::stdin().read_line(&mut minutes_input).expect("Failed to read line");
let reminder_minutes: u32 = minutes_input.trim().parse().expect("Failed to parse minutes");
// TODO: Erstelle eine Alert-Benachrichtigung mit der alert_message
// TODO: Erstelle eine Reminder-Benachrichtigung mit reminder_title und reminder_minutes
// TODO: Erstelle eine Dismiss-Benachrichtigung
// TODO: Gib jede Benachrichtigung mit Debug-Formatierung {:?} aus
// Jede Benachrichtigung sollte in einer eigenen Zeile ausgegeben werden
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Object Oriented Programming
1Methoden und Verhalten
Einführung in ImplementierungsblöckeDer Self-ParameterVeränderliche MethodenAssoziierte FunktionenMehrere ImplementierungsblöckeMethod ChainingRückblick – Rechteck-Aktionen4Projekt: Virtuelles Haustier
Das Haustier definierenDas Haustier füttern7Standard-Traits
Das Debug-TraitDas Display-TraitClone und CopyGleichheits-TraitsZusammenfassung – Druckbarer Punkt10Projekt: Dokumentensystem
Das Draw-TraitText-Komponente2Kapselung und Module
Grundlagen der ModuleDas Public-SchlüsselwortPrivate FelderGetterSetterWiederholung – Sicherer Tresor5Generics
Generische StructsGenerische MethodenMehrere generische TypenGenerische FunktionenZusammenfassung - Koordinatenpunkt8Traits als Einschränkungen
Syntax für Trait BoundsMehrfache BoundsDie Where-KlauselTypen mit Traits zurückgebenRückblick – Generischer Drucker11Design Patterns in Rust
Newtype-PatternKompositionDas Drop-TraitFrom und IntoZusammenfassung – Smart Pointer Mock3Fortgeschrittene Enums
Enums mit DatenMethoden für EnumsMatching von DatenvariantenDas Option-Enum erneut betrachtetZusammenfassung – Shape-Enum6Definition von Traits
Was ist ein Trait?Traits implementierenStandardimplementierungenStandardimplementierungen überschreibenTraits mit ParameternZusammenfassung – Media Player