Enumerazioni con dati
Fa parte della sezione Programmazione orientata agli oggetti del percorso Rust di Coddy. Lezione 14 di 61.
Gli enum di base in Rust ti permettono di definire un tipo con un insieme fisso di varianti, come Direction::North o Status::Active. Ma gli enum di Rust sono molto più potenti. Ogni variante può contenere i propri dati, rendendo gli enum incredibilmente flessibili per modellare scenari del mondo reale.
Considera un sistema di messaggistica in cui diversi tipi di messaggio trasportano informazioni diverse. Un messaggio di testo ha un contenuto, un comando di movimento ha delle coordinate e un segnale di uscita non ha proprio nulla. In Rust, puoi rappresentare tutto questo con un unico enum:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}
Ogni variante ha una forma diversa. Quit non contiene dati: è solo un segnale.
Move usa una sintassi simile a quella delle struct con campi denominati. Write contiene una singola String usando la sintassi delle tuple. ChangeColor contiene tre valori che rappresentano le componenti RGB.
Creare istanze di queste varianti è così:
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);
La bellezza di questo approccio è che m1, m2, m3 e m4 sono tutti dello stesso tipo: Message. Puoi memorizzarli nella stessa collezione, passarli alla stessa funzione o restituire qualsiasi variante da un'unica funzione. L'enum riunisce forme di dati diverse sotto un unico tipo, preservando le informazioni specifiche di cui ogni variante ha bisogno.
Sfida
FacileCostruiamo un sistema di notifiche che usa enum con dati per rappresentare diversi tipi di avvisi. Ogni tipo di notifica contiene informazioni diverse: alcune hanno messaggi, alcune valori numerici e alcune sono semplici segnali.
Creerai due file per organizzare il codice:
notification.rs: definisci un enum pubblicoNotificationcon tre varianti:Alert: contiene un singolo messaggioString(sintassi a tupla)Reminder: contiene campi con nome:title(String) eminutes(u32)Dismiss: non contiene dati, solo un segnale
main.rs: importa il modulo delle notifiche e crea un'istanza di ciascuna variante. Poi stampa le informazioni su ogni notifica per dimostrare che tutte e tre le varianti sono dello stesso tipo, ma contengono dati diversi.
Per la stampa, usa la formattazione di debug ({:?}) per visualizzare ogni notifica. Dovrai derivare il tratto Debug sul tuo enum affinché possa essere stampato in questo modo.
L'output dovrebbe mostrare tutte e tre le notifiche, ciascuna su una riga separata:
Alert("{message}")
Reminder { title: "{title}", minutes: {minutes} }
DismissAd esempio, con un messaggio di avviso "Server down", un promemoria con titolo "Meeting" e 30 minuti, l'output sarebbe:
Alert("Server down")
Reminder { title: "Meeting", minutes: 30 }
DismissRiceverai tre input: il messaggio di avviso, il titolo del promemoria e i minuti del promemoria.
Provalo tu
mod notification;
use notification::Notification;
fn main() {
// Leggi gli input
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: Crea una notifica Alert usando alert_message
// TODO: Crea una notifica Reminder usando reminder_title e reminder_minutes
// TODO: Crea una notifica Dismiss
// TODO: Stampa ogni notifica usando la formattazione di debug {:?}
// Ogni notifica deve essere stampata su una riga separata
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Metodi e comportamento
Introduzione ai blocchi implIl parametro selfMetodi mutabiliFunzioni associateBlocchi impl multipliConcatenamento di metodiRiepilogo - Azioni sul rettangolo4Progetto: animale domestico virtuale
Definire l'animaleNutrire l'animale7Trait standard
Il trait DebugIl trait DisplayClone e CopyTrait di uguaglianzaRiepilogo - Punto stampabile10Progetto: sistema di documenti
Il trait DrawComponente di testo2Incapsulamento e moduli
Nozioni di base sui moduliLa parola chiave publicCampi privatiGetterSetterRiepilogo - Armadietto sicuro5Generics
Struct genericheMetodi genericiPiù tipi genericiFunzioni genericheRipasso - Punto di coordinate8I Trait come vincoli
Sintassi dei vincoli sui traitVincoli multipliLa clausola whereRestituire tipi con i traitRiepilogo - Stampante generica11Modelli di progettazione in Rust
Pattern NewtypeComposizioneIl trait DropFrom e IntoRipasso - Mock con smart pointer3Enumerazioni avanzate
Enumerazioni con datiMetodi sulle enumerazioniCorrispondenza delle varianti con datiL'enumerazione Option ripresaRiepilogo - enumerazione Shape6Definizione dei trait
Che cos’è un trait?Implementare i traitImplementazioni predefiniteSovrascrivere le implementazioni predefiniteTrait con parametriRiepilogo - Lettore multimedialeEsercitati da solo: Compilatore Rust online