> For the complete documentation index, see [llms.txt](https://swift.unicorndonkeys.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://swift.unicorndonkeys.com/guida-al-linguaggio/enumerazioni.md).

# Enumerazioni (Enumerations)

Modella tipi personalizzati che definiscono un elenco di valori possibili.

Un'*enumerazione* definisce un tipo comune per un gruppo di valori correlati e ti permette di lavorare con quei valori in modo sicuro rispetto ai tipi all'interno del tuo codice.

Se conosci il C, saprai che le enumerazioni del C assegnano nomi correlati a un insieme di valori interi. Le enumerazioni in Swift sono molto più flessibili, e non devono fornire un valore per ogni caso dell'enumerazione. Se viene fornito un valore (noto come valore *grezzo*, o raw value) per ogni caso dell'enumerazione, il valore può essere una stringa, un carattere, o un valore di qualsiasi tipo intero o in virgola mobile.

In alternativa, i casi di un'enumerazione possono specificare valori associati di *qualsiasi* tipo da memorizzare insieme a ciascun diverso valore di caso, in modo molto simile a quanto fanno le union o i variant in altri linguaggi. Puoi definire un insieme comune di casi correlati come parte di un'unica enumerazione, ciascuno dei quali ha associato un diverso insieme di valori dei tipi appropriati.

In Swift le enumerazioni sono tipi di prima classe a pieno titolo. Adottano molte funzionalità tradizionalmente supportate solo dalle classi, come le proprietà calcolate, per fornire informazioni aggiuntive sul valore corrente dell'enumerazione, e i metodi di istanza, per fornire funzionalità legate ai valori che l'enumerazione rappresenta. Le enumerazioni possono anche definire inizializzatori per fornire un valore di caso iniziale; possono essere estese per espandere la loro funzionalità oltre la loro implementazione originale; e possono essere conformi a protocolli per fornire funzionalità standard.

Per saperne di più su queste capacità, vedi [Proprietà](/guida-al-linguaggio/proprieta.md), [Metodi](/guida-al-linguaggio/metodi.md), [Inizializzazione](/guida-al-linguaggio/inizializzazione.md), [Estensioni](/guida-al-linguaggio/estensioni.md) e [Protocolli](/guida-al-linguaggio/protocolli.md).

## Sintassi delle enumerazioni <a href="#sintassi-delle-enumerazioni" id="sintassi-delle-enumerazioni"></a>

Introduci le enumerazioni con la parola chiave `enum` e collochi la loro intera definizione all'interno di una coppia di parentesi graffe:

```swift
enum SomeEnumeration {
    // qui va la definizione dell'enumerazione
}
```

Ecco un esempio per i quattro punti cardinali di una bussola:

```swift
enum CompassPoint {
    case north
    case south
    case east
    case west
}
```

I valori definiti in un'enumerazione (come `north`, `south`, `east` e `west`) sono i suoi *casi di enumerazione*. Usi la parola chiave `case` per introdurre nuovi casi di enumerazione.

{% hint style="info" %}
**Nota:** I casi delle enumerazioni di Swift non hanno un valore intero impostato per impostazione predefinita, a differenza di linguaggi come C e Objective-C. Nell'esempio `CompassPoint` qui sopra, `north`, `south`, `east` e `west` non equivalgono implicitamente a `0`, `1`, `2` e `3`. Invece, i diversi casi dell'enumerazione sono valori a pieno titolo, con un tipo esplicitamente definito `CompassPoint`.
{% endhint %}

Più casi possono comparire su un'unica riga, separati da virgole:

```swift
enum Planet {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
```

Ogni definizione di enumerazione definisce un nuovo tipo. Come gli altri tipi in Swift, i loro nomi (come `CompassPoint` e `Planet`) iniziano con una lettera maiuscola. Assegna ai tipi enumerazione nomi al singolare anziché al plurale, in modo che si leggano in modo naturale:

```swift
var directionToHead = CompassPoint.west
```

Il tipo di `directionToHead` viene inferito quando viene inizializzata con uno dei possibili valori di `CompassPoint`. Una volta che `directionToHead` è dichiarata come `CompassPoint`, puoi impostarla a un diverso valore di `CompassPoint` usando una sintassi a punto più breve:

```swift
directionToHead = .east
```

Il tipo di `directionToHead` è già noto, e quindi puoi omettere il tipo quando ne imposti il valore. Questo rende il codice altamente leggibile quando si lavora con valori di enumerazione tipizzati esplicitamente.

## Confrontare i valori di un'enumerazione con un'istruzione switch <a href="#confrontare-i-valori-di-unenumerazione-con-unistruzione-switch" id="confrontare-i-valori-di-unenumerazione-con-unistruzione-switch"></a>

Puoi confrontare singoli valori di un'enumerazione con un'istruzione `switch`:

```swift
directionToHead = .south
switch directionToHead {
case .north:
    print("Lots of planets have a north")
case .south:
    print("Watch out for penguins")
case .east:
    print("Where the sun rises")
case .west:
    print("Where the skies are blue")
}
// Stampa "Watch out for penguins".
```

Puoi leggere questo codice come:

“Considera il valore di `directionToHead`. Nel caso in cui sia uguale a `.north`, stampa `"Lots of planets have a north"`. Nel caso in cui sia uguale a `.south`, stampa `"Watch out for penguins"`.”

…e così via.

Come descritto in [Flusso di controllo](/guida-al-linguaggio/flusso-di-controllo.md), un'istruzione `switch` deve essere esaustiva quando considera i casi di un'enumerazione. Se il `case` per `.west` viene omesso, questo codice non viene compilato, perché non considera l'elenco completo dei casi di `CompassPoint`. Richiedere l'esaustività garantisce che nessun caso dell'enumerazione venga omesso per errore.

Quando non è appropriato fornire un `case` per ogni caso dell'enumerazione, puoi fornire un caso `default` per coprire tutti i casi che non sono trattati esplicitamente:

```swift
let somePlanet = Planet.earth
switch somePlanet {
case .earth:
    print("Mostly harmless")
default:
    print("Not a safe place for humans")
}
// Stampa "Mostly harmless".
```

## Iterare sui casi di un'enumerazione <a href="#iterare-sui-casi-di-unenumerazione" id="iterare-sui-casi-di-unenumerazione"></a>

Per alcune enumerazioni, è utile avere una collezione di tutti i casi di quell'enumerazione. Lo abiliti scrivendo `: CaseIterable` dopo il nome dell'enumerazione. Swift espone una collezione di tutti i casi come proprietà `allCases` del tipo enumerazione. Ecco un esempio:

```swift
enum Beverage: CaseIterable {
    case coffee, tea, juice
}
let numberOfChoices = Beverage.allCases.count
print("\(numberOfChoices) beverages available")
// Stampa "3 beverages available".
```

Nell'esempio qui sopra, scrivi `Beverage.allCases` per accedere a una collezione che contiene tutti i casi dell'enumerazione `Beverage`. Puoi usare `allCases` come qualsiasi altra collezione — gli elementi della collezione sono istanze del tipo enumerazione, quindi in questo caso sono valori `Beverage`. L'esempio qui sopra conta quanti casi ci sono, e l'esempio seguente usa un ciclo `for`-`in` per iterare su tutti i casi.

```swift
for beverage in Beverage.allCases {
    print(beverage)
}
// coffee
// tea
// juice
```

La sintassi usata negli esempi qui sopra contrassegna l'enumerazione come conforme al protocollo [`CaseIterable`](https://developer.apple.com/documentation/swift/caseiterable). Per informazioni sui protocolli, vedi [Protocolli](/guida-al-linguaggio/protocolli.md).

## Valori associati <a href="#valori-associati" id="valori-associati"></a>

Gli esempi della sezione precedente mostrano come i casi di un'enumerazione siano un valore definito (e tipizzato) a pieno titolo. Puoi impostare una costante o una variabile a `Planet.earth`, e verificare questo valore in seguito. Tuttavia, a volte è utile poter memorizzare valori di altri tipi insieme a questi valori di caso. Queste informazioni aggiuntive sono chiamate *valore associato*, e variano ogni volta che usi quel caso come valore nel tuo codice.

Puoi definire enumerazioni Swift che memorizzano valori associati di qualsiasi tipo, e i tipi dei valori possono essere diversi per ciascun caso dell'enumerazione, se necessario. Enumerazioni simili a queste sono note come *unioni discriminate*, *unioni etichettate* (tagged union) o *variant* in altri linguaggi di programmazione.

Per esempio, supponi che un sistema di gestione dell'inventario debba tracciare i prodotti tramite due diversi tipi di codice a barre. Alcuni prodotti sono etichettati con codici a barre 1D in formato UPC, che usa i numeri da `0` a `9`. Ogni codice a barre ha una cifra di sistema numerico, seguita da cinque cifre di codice del produttore e cinque cifre di codice del prodotto. Queste sono seguite da una cifra di controllo per verificare che il codice sia stato scansionato correttamente:

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FKG8PnlCoZTvqbojQDzjS%2Fbarcode_UPC%402x.png?alt=media)

Altri prodotti sono etichettati con codici a barre 2D in formato QR code, che possono usare qualsiasi carattere ISO 8859-1 e possono codificare una stringa lunga fino a 2.953 caratteri:

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FfTcsWKBmNYQGmfmU5EJl%2Fbarcode_QR%402x.png?alt=media)

Per un sistema di gestione dell'inventario è comodo memorizzare i codici a barre UPC come una tupla di quattro interi, e i codici a barre QR code come una stringa di qualsiasi lunghezza.

In Swift, un'enumerazione per definire codici a barre di prodotto di entrambi i tipi potrebbe apparire così:

```swift
enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}
```

Questo può essere letto come:

“Definisci un tipo enumerazione chiamato `Barcode`, che può assumere un valore `upc` con un valore associato di tipo (`Int`, `Int`, `Int`, `Int`), oppure un valore `qrCode` con un valore associato di tipo `String`.”

Questa definizione non fornisce alcun valore `Int` o `String` effettivo — definisce soltanto il *tipo* dei valori associati che le costanti e le variabili `Barcode` possono memorizzare quando sono uguali a `Barcode.upc` o a `Barcode.qrCode`.

Puoi quindi creare nuovi codici a barre usando uno dei due tipi:

```swift
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
```

Questo esempio crea una nuova variabile chiamata `productBarcode` e le assegna un valore `Barcode.upc` con un valore tupla associato pari a `(8, 85909, 51226, 3)`.

Puoi assegnare allo stesso prodotto un tipo diverso di codice a barre:

```swift
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
```

A questo punto, il `Barcode.upc` originale e i suoi valori interi vengono sostituiti dal nuovo `Barcode.qrCode` e dal suo valore stringa. Le costanti e le variabili di tipo `Barcode` possono memorizzare un `.upc` oppure un `.qrCode` (insieme ai loro valori associati), ma possono memorizzarne soltanto uno alla volta.

Puoi verificare i diversi tipi di codice a barre usando un'istruzione switch, in modo simile all'esempio in [Confrontare i valori di un'enumerazione con un'istruzione switch](/guida-al-linguaggio/enumerazioni.md#confrontare-i-valori-di-unenumerazione-con-unistruzione-switch). Questa volta, però, i valori associati vengono estratti come parte dell'istruzione switch. Estrai ciascun valore associato come costante (con il prefisso `let`) o come variabile (con il prefisso `var`) da usare all'interno del corpo del caso dello `switch`:

```swift
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
    print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case .qrCode(let productCode):
    print("QR code: \(productCode).")
}
// Stampa "QR code: ABCDEFGHIJKLMNOP."
```

Se tutti i valori associati di un caso dell'enumerazione vengono estratti come costanti, o se vengono tutti estratti come variabili, per brevità puoi collocare un'unica annotazione `let` o `var` prima del nome del caso:

```swift
switch productBarcode {
case let .upc(numberSystem, manufacturer, product, check):
    print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode):
    print("QR code: \(productCode).")
}
// Stampa "QR code: ABCDEFGHIJKLMNOP."
```

Quando confronti un solo caso di un'enumerazione — per esempio, per estrarne il valore associato — puoi usare un'istruzione `if`-`case` invece di scrivere un'istruzione switch completa. Ecco come appare:

```swift
if case .qrCode(let productCode) = productBarcode {
    print("QR code: \(productCode).")
}
```

Proprio come nell'istruzione switch precedente, qui la variabile `productBarcode` viene confrontata con il pattern `.qrCode(let productCode)`. E come nel caso dello switch, scrivere `let` estrae il valore associato come costante. Per maggiori informazioni sulle istruzioni `if`-`case`, vedi [Pattern](/guida-al-linguaggio/flusso-di-controllo.md#pattern).

## Valori grezzi <a href="#valori-grezzi" id="valori-grezzi"></a>

L'esempio dei codici a barre in [Valori associati](/guida-al-linguaggio/enumerazioni.md#valori-associati) mostra come i casi di un'enumerazione possano dichiarare di memorizzare valori associati di tipi diversi. In alternativa ai valori associati, i casi di un'enumerazione possono essere prepopolati con valori predefiniti (chiamati *valori grezzi*, o raw value), che sono tutti dello stesso tipo.

Ecco un esempio che memorizza valori ASCII grezzi insieme a casi di enumerazione con nome:

```swift
enum ASCIIControlCharacter: Character {
    case tab = "\t"
    case lineFeed = "\n"
    case carriageReturn = "\r"
}
```

Qui, i valori grezzi di un'enumerazione chiamata `ASCIIControlCharacter` sono definiti di tipo `Character`, e sono impostati ad alcuni dei caratteri di controllo ASCII più comuni. I valori `Character` sono descritti in [Stringhe e caratteri](/guida-al-linguaggio/stringhe-e-caratteri.md).

I valori grezzi possono essere stringhe, caratteri o qualsiasi tipo numerico intero o in virgola mobile. Ogni valore grezzo deve essere unico all'interno della dichiarazione della sua enumerazione.

Sebbene tu possa usare sia i valori grezzi sia i valori associati per dare a un'enumerazione un valore aggiuntivo, è importante comprendere la differenza tra i due. Scegli il valore grezzo di un caso dell'enumerazione quando definisci quel caso nel tuo codice, come i tre codici ASCII qui sopra. Il valore grezzo di un particolare caso di enumerazione è sempre lo stesso. Al contrario, scegli i valori associati quando crei una nuova costante o variabile usando uno dei casi dell'enumerazione, e puoi scegliere un valore diverso ogni volta che lo fai.

### Valori grezzi assegnati implicitamente <a href="#valori-grezzi-assegnati-implicitamente" id="valori-grezzi-assegnati-implicitamente"></a>

Quando lavori con enumerazioni che memorizzano valori grezzi interi o stringa, non devi assegnare esplicitamente un valore grezzo per ogni caso. Quando non lo fai, Swift assegna automaticamente i valori per te.

Per esempio, quando per i valori grezzi si usano interi, il valore implicito di ciascun caso è pari al caso precedente più uno. Se il primo caso non ha un valore impostato, il suo valore è `0`.

L'enumerazione seguente è un perfezionamento della precedente enumerazione `Planet`, con valori grezzi interi per rappresentare l'ordine di ciascun pianeta a partire dal sole:

```swift
enum Planet: Int {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
```

Nell'esempio qui sopra, `Planet.mercury` ha un valore grezzo esplicito di `1`, `Planet.venus` ha un valore grezzo implicito di `2`, e così via.

Quando per i valori grezzi si usano stringhe, il valore implicito di ciascun caso è il testo del nome di quel caso.

L'enumerazione seguente è un perfezionamento della precedente enumerazione `CompassPoint`, con valori grezzi stringa per rappresentare il nome di ciascuna direzione:

```swift
enum CompassPoint: String {
    case north, south, east, west
}
```

Nell'esempio qui sopra, `CompassPoint.south` ha un valore grezzo implicito di `"south"`, e così via.

Accedi al valore grezzo di un caso di enumerazione con la sua proprietà `rawValue`:

```swift
let earthsOrder = Planet.earth.rawValue
// earthsOrder vale 3

let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection vale "west"
```

### Inizializzare da un valore grezzo <a href="#inizializzare-da-un-valore-grezzo" id="inizializzare-da-un-valore-grezzo"></a>

Se definisci un'enumerazione con un tipo di valore grezzo, l'enumerazione riceve automaticamente un inizializzatore che accetta un valore del tipo del valore grezzo (come parametro chiamato `rawValue`) e restituisce un caso dell'enumerazione oppure `nil`. Puoi usare questo inizializzatore per provare a creare una nuova istanza dell'enumerazione.

Questo esempio identifica Urano a partire dal suo valore grezzo `7`:

```swift
let possiblePlanet = Planet(rawValue: 7)
// possiblePlanet è di tipo Planet? ed è uguale a Planet.uranus
```

Tuttavia, non tutti i possibili valori `Int` troveranno un pianeta corrispondente. Per questo motivo, l'inizializzatore da valore grezzo restituisce sempre un caso di enumerazione *opzionale*. Nell'esempio qui sopra, `possiblePlanet` è di tipo `Planet?`, ovvero “`Planet` opzionale”.

{% hint style="info" %}
**Nota:** L'inizializzatore da valore grezzo è un inizializzatore failable, perché non ogni valore grezzo restituirà un caso di enumerazione. Per maggiori informazioni, vedi [Inizializzatori failable](/riferimento-del-linguaggio/dichiarazioni.md#inizializzatori-failable).
{% endhint %}

Se provi a trovare un pianeta in posizione `11`, il valore `Planet` opzionale restituito dall'inizializzatore da valore grezzo sarà `nil`:

```swift
let positionToFind = 11
if let somePlanet = Planet(rawValue: positionToFind) {
    switch somePlanet {
    case .earth:
        print("Mostly harmless")
    default:
        print("Not a safe place for humans")
    }
} else {
    print("There isn't a planet at position \(positionToFind)")
}
// Stampa "There isn't a planet at position 11".
```

Questo esempio usa l'optional binding per provare ad accedere a un pianeta con un valore grezzo di `11`. L'istruzione `if let somePlanet = Planet(rawValue: 11)` crea un `Planet` opzionale, e imposta `somePlanet` al valore di quel `Planet` opzionale se può essere recuperato. In questo caso, non è possibile recuperare un pianeta in posizione `11`, e quindi viene eseguito invece il ramo `else`.

## Enumerazioni ricorsive <a href="#enumerazioni-ricorsive" id="enumerazioni-ricorsive"></a>

Un'*enumerazione ricorsiva* è un'enumerazione che ha un'altra istanza dell'enumerazione come valore associato per uno o più dei casi dell'enumerazione. Indichi che un caso di enumerazione è ricorsivo scrivendo `indirect` prima di esso, il che dice al compilatore di inserire il necessario livello di indirezione.

Per esempio, ecco un'enumerazione che memorizza semplici espressioni aritmetiche:

```swift
enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
```

Puoi anche scrivere `indirect` prima dell'inizio dell'enumerazione per abilitare l'indirezione per tutti i casi dell'enumerazione che hanno un valore associato:

```swift
indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}
```

Questa enumerazione può memorizzare tre tipi di espressioni aritmetiche: un semplice numero, l'addizione di due espressioni, e la moltiplicazione di due espressioni. I casi `addition` e `multiplication` hanno valori associati che sono anch'essi espressioni aritmetiche — questi valori associati rendono possibile annidare le espressioni. Per esempio, l'espressione `(5 + 4) * 2` ha un numero sul lato destro della moltiplicazione e un'altra espressione sul lato sinistro della moltiplicazione. Poiché i dati sono annidati, anche l'enumerazione usata per memorizzarli deve supportare l'annidamento — ciò significa che l'enumerazione deve essere ricorsiva. Il codice seguente mostra la creazione dell'enumerazione ricorsiva `ArithmeticExpression` per `(5 + 4) * 2`:

```swift
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
```

Una funzione ricorsiva è un modo diretto per lavorare con dati che hanno una struttura ricorsiva. Per esempio, ecco una funzione che valuta un'espressione aritmetica:

```swift
func evaluate(_ expression: ArithmeticExpression) -> Int {
    switch expression {
    case let .number(value):
        return value
    case let .addition(left, right):
        return evaluate(left) + evaluate(right)
    case let .multiplication(left, right):
        return evaluate(left) * evaluate(right)
    }
}

print(evaluate(product))
// Stampa "18".
```

Questa funzione valuta un semplice numero restituendo semplicemente il valore associato. Valuta un'addizione o una moltiplicazione valutando l'espressione sul lato sinistro, valutando l'espressione sul lato destro, e poi sommandole o moltiplicandole.
