Corrispondenza delle varianti con dati
Fa parte della sezione Programmazione orientata agli oggetti del percorso Rust di Coddy. Lezione 16 di 61.
Nella lezione precedente, hai usato match all'interno dei metodi degli enum per gestire varianti diverse. Ora concentriamoci su come match estrae effettivamente i dati memorizzati all'interno di queste varianti: una tecnica chiamata destrutturazione.
Quando esegui un match su una variante di un enum che contiene dati, puoi associare quei dati a variabili direttamente nel pattern:
enum Event {
Click { x: i32, y: i32 },
KeyPress(char),
Resize(u32, u32),
}
fn handle_event(event: Event) {
match event {
Event::Click { x, y } => {
println!("Clicked at ({}, {})", x, y);
}
Event::KeyPress(key) => {
println!("Key pressed: {}", key);
}
Event::Resize(width, height) => {
println!("Resized to {}x{}", width, height);
}
}
}
Ogni ramo estrae i dati in modo diverso in base alla struttura della variante. Per le varianti simili a struct, usi { field_name } per estrarre i campi con nome. Per le varianti di tupla, usi variabili posizionali come (width, height).
I nomi delle variabili che scegli diventano disponibili all'interno di quel ramo del match. Questo è potente perché allo stesso tempo verifichi quale variante hai e accedi al suo payload.
Il compilatore si assicura che tu gestisca ogni variante e i valori estratti sono subito pronti all’uso: non servono passaggi aggiuntivi.
Sfida
FacileCreiamo un processore di comandi che gestisce diversi tipi di comandi utente. Ogni comando contiene dati diversi e il tuo processore userà il pattern matching per estrarre quei dati e produrre le risposte appropriate.
Creerai due file per organizzare il codice:
command.rs: Definisci un'enum pubblicaCommandcon tre varianti:Say: contiene un singolo messaggioString(sintassi a tupla)Move: contiene campi con nome:direction(String) esteps(u32)Calculate: contiene due valorii32che rappresentano i numeri da sommare (sintassi a tupla)
executeche usamatchper destrutturare ogni variante e restituire unaStringche descrive l'azione eseguita.main.rs: Importa il modulo dei comandi, crea un'istanza di ciascuna variante del comando usando gli input forniti e chiama il metodoexecutesu ciascuna per stampare i risultati.
Il metodo execute deve destrutturare ogni variante per accedere ai suoi dati e restituire messaggi nei seguenti formati esatti:
- Per
Say:Saying: {message} - Per
Move:Moving {steps} steps {direction} - Per
Calculate:{a} + {b} = {sum}
L'output deve mostrare il risultato di ciascun comando su una riga a sé:
Saying: {message}
Moving {steps} steps {direction}
{a} + {b} = {sum}Per esempio, con un messaggio per Say pari a "Hello world", uno spostamento di 5 passi verso "north" e un calcolo con 10 e 25, l'output sarebbe:
Saying: Hello world
Moving 5 steps north
10 + 25 = 35Riceverai cinque input: il messaggio per Say, la direzione, il numero di passi e i due numeri da calcolare.
Provalo tu
mod command;
use command::Command;
fn main() {
// Leggi gli input
let mut say_message = String::new();
std::io::stdin().read_line(&mut say_message).expect("Failed to read line");
let say_message = say_message.trim().to_string();
let mut direction = String::new();
std::io::stdin().read_line(&mut direction).expect("Failed to read line");
let direction = direction.trim().to_string();
let mut steps_input = String::new();
std::io::stdin().read_line(&mut steps_input).expect("Failed to read line");
let steps: u32 = steps_input.trim().parse().expect("Failed to parse steps");
let mut num1_input = String::new();
std::io::stdin().read_line(&mut num1_input).expect("Failed to read line");
let num1: i32 = num1_input.trim().parse().expect("Failed to parse num1");
let mut num2_input = String::new();
std::io::stdin().read_line(&mut num2_input).expect("Failed to read line");
let num2: i32 = num2_input.trim().parse().expect("Failed to parse num2");
// TODO: Crea un comando Say usando say_message ed eseguilo
// TODO: Crea un comando Move usando direction e steps, ed eseguilo
// TODO: Crea un comando Calculate usando num1 e num2, ed eseguilo
// TODO: Stampa i risultati dell'esecuzione di ciascun comando
}
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