Le enumerations sono un tipo di dato che rappresenta un gruppo di valori correlati; in C e Objective-C permettono di assegnare dei nomi ad un set di valori di tipo intero mentre in Swift le enumerations rappresentano uno strumento molto più flessibile e potente.
La sintassi è molto semplice: attraverso la keyword enum è possibile definire una nuova enumeration; trattandosi di un tipo di dato è importante ricordare che in Swift deve cominciare con una lettera maiuscola:
1 2 3 |
enum TestEnum { // inserire definizione per l'enum } |
L’esempio precedente rappresenta lo scheletro vuoto di una enumeration (quindi assolutamente inutile). Aggiungiamo i possibili valori, o per essere più precisi gli enumeration cases.
1 2 3 4 5 6 |
enum TestEnum { case uno case due case tre case quattro } |
A differenza di Objective-C ad ogni enumeration case non viene assegnato automaticamente un valore di tipo intero; per cui se non si assegnano esplicitamente i valori, la stessa enumeration può essere scritta raggruppando i cases:
1 2 3 |
enum TestEnum { case uno, due, tre, quattro } |
A questo punto è possibile usare l’enumeration appena definita:
1 2 |
var primoEsempioVarEnum: TestEnum = .uno var secondoEsempioVarEnum = TestEnum.due |
nel primo caso ( primoEsempioVarEnum ) è dichiarato esplicitamente il tipo della variabile, nel seccondo ( secondoEsempioVarEnum ) invece viene dedotto automaticamente dall’assegnazione.
E’ ovviamente possibile utilizzare uno switch per confrontare e gestire i singoli case:
1 2 3 4 5 6 7 8 9 10 11 12 |
var mioEnum = TestEnum.uno switch mioEnum { case .uno: print("caso uno") case .due: print("caso due") case .tre: print("caso tre") case .quattro: print("caso quattro") } |
In swift quando si usa uno switch per processare i possibili case di un enumerations, devono essere presenti tutti i casi affinchè il codice sia compilato (a switch must be exhaustive); in alternativa si può usare un default per gestire i case dell’enumeration non esplicitamente gestiti:
1 2 3 4 5 6 7 8 |
var mioEnum = TestEnum.uno switch mioEnum { case .uno: print("caso uno") default: print("altri casi") } |
Associated Values
Le associated values permettono di associare un valore ad un case di un enumeration in fase di inizializzazione:
1 2 3 4 5 6 7 8 9 |
enum TestEnum { case uno(Int) case due(Int) case tre(Int) case quattro(String) } var mioEnum1 = TestEnum.uno(22) var mioEnum2 = TestEnum.quattro("valore") |
Come è chiaramente visibile nell’esempio è possibile definire tipi di dati diversi per i singoli case.
Per accedere ai valori associati di un enumeration è necessario usare l’istruzione switch:
1 2 3 4 5 6 7 8 9 10 |
switch mioEnum { case let .uno(numero): print("\(numero)") case let .due(numero): print("\(numero)") case let .tre(numero): print("\(numero)") case let .quattro(stringa): print(stringa) } |
Non è possibile accedere direttamente al valore associato senza uno switch ma è possibile farlo in maniera più conveniente utilizzando una funzione o una proprietà all’interno dell’enumeration (come spiegato all’interno del paragrafo Proprietà e funzioni).
Raw Values
E’ possibile associare in fase di definizione dell’enumaration un valore di default ai singoli case
1 2 3 4 5 6 7 8 9 10 11 |
enum TestEnum : Int { case uno = 1 case due = 2 case tre = 3 case quattro = 4 } var mioEnum: TestEnum mioEnum = .One print("\(mioEnum.rawValue)") //stampa 1 |
A differenza di quanto definito in precedenza per gli associated values, il tipo di dato deve essere il medesimo per tutti i
case dell’enumeration.
Possiamo definire anche solo il valore di default per il primo case:
1 2 3 |
enum TestEnum : Int { case uno = 1, due, tre, quattro } |
In questo esempio TestEnum.uno ha un valore esplicitamente definito uguale a 1; i valori degli altri case vengono assegnati automaticamente: TestEnum.due avrà un valore uguale a 2 e così via. Sono chiamati Implicitly Assigned Raw Values e possono essere utilizzati con enumerations i cui valori di default siano interi o stringhe.
1 2 3 4 5 6 7 8 |
enum PuntiCardinali: String { case nord, sud, est, ovest } var mioEnum: PuntiCardinali mioEnum = .sud print("\(mioEnum.rawValue)") //stampa sud |
Nell’esempio precedente PuntiCardinali.nord ha un valore di default implicito uguale a “nord”.
Proprietà e funzioni
Le enumerations possono anche contenere funzioni e proprietà:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
enum TestEnum { case uno(Int) case due(Int) case tre(Int) func valoreAssociato() -> String { switch self { case let .uno(valore): return("\(valore)") case let .due(valore): return("\(valore)") case let .tre(valore): return("\(valore)") } } } var mioEnum: TestEnum mioEnum = .uno(55) print(mioEnum.valoreAssociato()) //stampa 55 |
Enumeration Ricorsive
Una enumerazione ricorsiva è una enumeration all’interno della quale uno o più case hanno come valore associato una istanza della stessa enumeration. Si usa la keyword indirect per definire un case ricorsivo:
1 2 3 4 5 6 7 8 9 10 11 |
enum EspressioneAritmetica { case numero(Int) indirect case addizione(EspressioneAritmetica, EspressioneAritmetica) indirect case sottrazione(EspressioneAritmetica, EspressioneAritmetica) indirect case moltiplicazione(EspressioneAritmetica, EspressioneAritmetica) indirect case divisione(EspressioneAritmetica, EspressioneAritmetica) } let tre = EspressioneAritmetica.numero(3) let quattro = EspressioneAritmetica.numero(4) let somma = EspressioneAritmetica.addizione(tre, quattro) |
Eì possibile utilizzare la keyword indirect anche prima di enum per abilitare l’enumerazione ricorsiva per tutti i case.
Una funzione ricorsiva è un modo semplice per lavorare con i dati che hanno una struttura ricorsiva. Ad esempio, ecco una funzione che valuta un’espressione aritmetica:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
let sei = EspressioneAritmetica.numero(6) let sette = EspressioneAritmetica.numero(7) let somma = EspressioneAritmetica.addizione(sei, sette) func calcola(_ expression: EspressioneAritmetica) -> Int { switch expression { case let .numero(value): return value case let .addizione(left, right): return calcola(left) + calcola(right) case let .sottrazione(left, right): return calcola(left) - calcola(right) case let .moltiplicazione(left, right): return calcola(left) * calcola(right) case let .divisione(left, right): return calcola(left) / calcola(right) } } print(calcola(somma)) // stampa 13 |