|
Altro interessante argomento relativo ai tipi definiti dall'utente è quello delle enumerazioni. Essi permettono di definire un tipo che può assumere una tra diversi possibili varianti. Ogni variante, che è proprio il nome di ciascuno degli elementi interni, dell'enumerativo, può essere semplice, senza dati, oppure può portare con sé dei dati. In parole povere, è un tipo definito dal programmatore che permette di selezionare un valore da un elenco. Diamo la solita definizione formale che si basa sulla keyword enum: enum Identificatore { Variante-1 [tipi opzionali], Variante-2 [tipi opzionali], ..... Variante-n [tipi opzionali], } gli identificatori sia per l'enumerativo che per le varianti dovrebbero seguire le consute regole CamelCase. I tipi abbinati alle singole varianti possono essere diversi tra loro, questo è importante, in conseguenza di ciò la varietà di situazioni che si presentano quando definite un enurmativo possono essere davvero tante, vediamo un possibile esempio: enum Mouse { Assente, Peso(u8), Posizione{x: i32, y: i32], Colore(string), } quindi abbiamo un primo campo che presenta solo un identificatore, un secondo che propone un tipo, un terzo che inserisce anche un nome per i tipo proposti (si notino le parentesi graffe) e un quarto che presenta un altro tipo. Ora presento un esempio nel quale troverete un costrutto di selezione molto importante, il pattern matching introdotto dalla keyword match. Potete dare uno sguardo all'apposito capitolo per comprenderlo bene sintatticamente, per il resto credo che il codice sia abbastanza intuitivo come funzionamento. Anche per la funzione usata potete consultare rapidamente l'apposito capitolo.
Nell'esempio (pur se poco significativo, una struct era ovviamente meglio) troviamo un po' tutte le casistiche possibili di definizione delle varianti (qui è più un elenco) di un enumerativo. La sinergia con il pattern matching è evidente. Non vi sarà sfuggito che qui l'operatore :: (double colon) vi permette di accedere alle varianti di un enumerativo. Un esempio un po' più classico è il seguente:
Ricordo che l’istruzione #[derive(Debug)] è un attributo che si applica a strutture o enumerazioni per auto-generare automaticamente l’implementazione del trait Debug. Questo trait permette di stampare le informazioni di una struttura in un formato utile per il debugging, utilizzando il formattatore {:?}. Come avete visto nella definizione formale ad inizio paragrafo, e come visto anche nella prima variante nell'esempio 16.1 i tipi sono opzionali e quindi possiamo definire un enumerativo senza tipi, che può essere utile quando non servono ulteriori informazioni al di là delle voci esposte, in questo modo ad esempio: enum Stato { Start, Stop, Pause, } Possiamo passare il valore di una variante ad un variabile usando il pattern matching o il costrutto if - let, purtroppo mi tocca dire anche qui "che vedremo più avanti":
Se invece volete che il valore persista all'infuori di match o if let potete fare così: let valore = match x01 { Test::X1(val) => val, }; e ora "valore" conterrà il nostro 9. Ovviamente una variante può essere anche di tipi più complessi ad esempio una struct o un altro enumerativo o magari un Option se può essere presente un campo senza valore. Ne vedremo un esempio nella sezione dedicata appunto agli esempi. Quando istanziamo un enumerativo possiamo usare il consueto mut. Se modifichiamo il main dell'esempio come di seguito: fn main(){ let mut rosso = Colore::Rosso; println!("{:?}", rosso); rosso = Colore::Giallo; println!("{:?}", rosso); } otteniamo:
Anche le enumerazioni saranno tra i protagonisti di interessanti interazioni con le funzioni. Aggiungo a questo punto un ulteriore esempio, abbastanza tipico appena un po' più complesso in quanto coinvolge, anticipandolo, il concetto di funzione, ma completo, di uso delle enumerazioni.
Quanto sono potenti le enumerazioni? Molto, direi più che in altri linguaggi che hanno costrutti analoghi. Tra l'altro ad essi possono essere associati dei metodi, proprio come per le struct. Vedremo questo aspetto più avanti. così come vedremo che, come per tanti altri costrutti, anche le enumerazioni possono collaborare con le funzioni. |