> 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/benvenuto-in-swift/un-tour-di-swift.md).

# Un tour di Swift (A Swift Tour)

Esplora le funzionalità e la sintassi di Swift.

La tradizione vuole che il primo programma in un nuovo linguaggio stampi sullo schermo le parole “Hello, world!”. In Swift, questo si può fare con una sola riga:

```swift
print("Hello, world!")
// Stampa "Hello, world!"
```

Questa sintassi dovrebbe sembrarti familiare se conosci un altro linguaggio — in Swift, questa riga di codice è un programma completo. Non hai bisogno di importare una libreria separata per funzionalità come l'output di testo o la gestione delle stringhe. Il codice scritto nell'ambito globale viene usato come punto di ingresso del programma, quindi non hai bisogno di una funzione `main()`. Non hai nemmeno bisogno di scrivere il punto e virgola alla fine di ogni istruzione.

Questo tour ti fornisce informazioni sufficienti per iniziare a scrivere codice in Swift mostrandoti come realizzare una varietà di compiti di programmazione. Non preoccuparti se non capisci qualcosa — tutto ciò che viene introdotto in questo tour è spiegato in dettaglio nel resto di questo libro.

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

Usa `let` per creare una costante e `var` per creare una variabile. Il valore di una costante non deve essere noto in fase di compilazione, ma devi assegnarle un valore esattamente una volta. Ciò significa che puoi usare le costanti per dare un nome a un valore che determini una volta sola ma usi in molti punti.

```swift
var myVariable = 42
myVariable = 50
let myConstant = 42
```

Una costante o una variabile deve avere lo stesso tipo del valore che vuoi assegnarle. Tuttavia, non devi sempre scrivere il tipo esplicitamente. Fornire un valore quando crei una costante o una variabile permette al compilatore di inferirne il tipo. Nell'esempio qui sopra, il compilatore inferisce che `myVariable` è un intero perché il suo valore iniziale è un intero.

Se il valore iniziale non fornisce informazioni sufficienti (o se non c'è un valore iniziale), specifica il tipo scrivendolo dopo la variabile, separato da due punti.

```swift
let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70
```

{% hint style="success" %}
**Esperimento:** Crea una costante con un tipo esplicito `Float` e un valore di `4`.
{% endhint %}

I valori non vengono mai convertiti implicitamente in un altro tipo. Se hai bisogno di convertire un valore in un tipo diverso, crea esplicitamente un'istanza del tipo desiderato.

```swift
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
```

{% hint style="success" %}
**Esperimento:** Prova a rimuovere la conversione in `String` dall'ultima riga. Che errore ottieni?
{% endhint %}

Esiste un modo ancora più semplice per includere valori nelle stringhe: scrivi il valore tra parentesi, e scrivi una barra rovesciata (`\`) prima delle parentesi. Per esempio:

```swift
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
```

{% hint style="success" %}
**Esperimento:** Usa `\()` per includere un calcolo in virgola mobile in una stringa e per includere il nome di qualcuno in un saluto.
{% endhint %}

Usa tre virgolette doppie (`"""`) per le stringhe che occupano più righe. L'indentazione all'inizio di ogni riga tra virgolette viene rimossa, purché corrisponda all'indentazione delle virgolette di chiusura. Per esempio:

```swift
let quotation = """
        Even though there's whitespace to the left,
        the actual lines aren't indented.
            Except for this line.
        Double quotes (") can appear without being escaped.

        I still have \(apples + oranges) pieces of fruit.
        """
```

Crea array e dizionari usando le parentesi quadre (`[]`), e accedi ai loro elementi scrivendo l'indice o la chiave tra parentesi quadre. Dopo l'ultimo elemento è consentita una virgola.

```swift
var fruits = ["strawberries", "limes", "tangerines"]
fruits[1] = "grapes"

var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
 ]
occupations["Jayne"] = "Public Relations"
```

Gli array crescono automaticamente man mano che aggiungi elementi.

```swift
fruits.append("blueberries")
print(fruits)
// Stampa "["strawberries", "grapes", "tangerines", "blueberries"]".
```

Le parentesi quadre si usano anche per scrivere un array o un dizionario vuoto. Per un array, scrivi `[]`, e per un dizionario, scrivi `[:]`.

```swift
fruits = []
occupations = [:]
```

Se stai assegnando un array o un dizionario vuoto a una nuova variabile, o in un altro punto in cui non ci sono informazioni di tipo, devi specificare il tipo.

```swift
let emptyArray: [String] = []
let emptyDictionary: [String: Float] = [:]
```

## Flusso di controllo <a href="#flusso-di-controllo" id="flusso-di-controllo"></a>

Usa `if` e `switch` per creare istruzioni condizionali, e usa `for`-`in`, `while` e `repeat`-`while` per creare cicli. Le parentesi attorno alla condizione o alla variabile del ciclo sono opzionali. Le parentesi graffe attorno al corpo sono obbligatorie.

```swift
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
    if score > 50 {
        teamScore += 3
    } else {
        teamScore += 1
    }
}
print(teamScore)
// Stampa "11".
```

In un'istruzione `if`, la condizione deve essere un'espressione booleana — ciò significa che codice come `if score { ... }` è un errore, non un confronto implicito con zero.

Puoi scrivere `if` o `switch` dopo il segno di uguale (`=`) di un assegnamento o dopo `return`, per scegliere un valore in base alla condizione.

```swift
let scoreDecoration = if teamScore > 10 {
    "🎉"
} else {
    ""
}
print("Score:", teamScore, scoreDecoration)
// Stampa "Score: 11 🎉".
```

Puoi usare `if` e `let` insieme per lavorare con valori che potrebbero mancare. Questi valori sono rappresentati come opzionali. Un valore opzionale contiene un valore oppure contiene `nil` per indicare che un valore manca. Scrivi un punto interrogativo (`?`) dopo il tipo di un valore per contrassegnare il valore come opzionale.

```swift
var optionalString: String? = "Hello"
print(optionalString == nil)
// Stampa "false".

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}
print(greeting)
```

{% hint style="success" %}
**Esperimento:** Cambia `optionalName` in `nil`. Quale saluto ottieni? Aggiungi una clausola `else` che imposti un saluto diverso se `optionalName` è `nil`.
{% endhint %}

Se il valore opzionale è `nil`, la condizione è `false` e il codice tra parentesi graffe viene saltato. Altrimenti, viene fatto l'unwrapping del valore opzionale e il risultato viene assegnato alla costante dopo `let`, il che rende il valore estratto disponibile all'interno del blocco di codice.

Un altro modo per gestire i valori opzionali è fornire un valore predefinito usando l'operatore `??`. Se il valore opzionale manca, viene usato al suo posto il valore predefinito.

```swift
let nickname: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickname ?? fullName)"
```

Puoi usare una forma più breve per fare l'unwrapping di un valore, usando lo stesso nome per il valore estratto.

```swift
if let nickname {
    print("Hey, \(nickname)")
}
// Non stampa nulla, perché nickname è nil.
```

Gli switch supportano qualsiasi tipo di dato e un'ampia varietà di operazioni di confronto — non sono limitati agli interi e ai test di uguaglianza.

```swift
let vegetable = "red pepper"
switch vegetable {
case "celery":
    print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
    print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
    print("Is it a spicy \(x)?")
default:
    print("Everything tastes good in soup.")
}
// Stampa "Is it a spicy red pepper?"
```

{% hint style="success" %}
**Esperimento:** Prova a rimuovere il caso default. Che errore ottieni?
{% endhint %}

Nota come `let` possa essere usato in un pattern per assegnare a una costante il valore che corrisponde al pattern.

Dopo aver eseguito il codice all'interno del caso dello switch che ha trovato corrispondenza, il programma esce dall'istruzione switch. L'esecuzione non prosegue con il caso successivo, quindi non hai bisogno di uscire esplicitamente dallo switch alla fine del codice di ciascun caso.

Usi `for`-`in` per iterare sugli elementi di un dizionario fornendo una coppia di nomi da usare per ciascuna coppia chiave-valore. I dizionari sono una collezione non ordinata, quindi le loro chiavi e i loro valori vengono iterati in un ordine arbitrario.

```swift
let interestingNumbers = [
    "Prime": [2, 3, 5, 7, 11, 13],
    "Fibonacci": [1, 1, 2, 3, 5, 8],
    "Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (_, numbers) in interestingNumbers {
    for number in numbers {
        if number > largest {
            largest = number
        }
    }
}
print(largest)
// Stampa "25".
```

{% hint style="success" %}
**Esperimento:** Sostituisci `_` con il nome di una variabile, e tieni traccia di quale tipo di numero era il più grande.
{% endhint %}

Usa `while` per ripetere un blocco di codice finché una condizione non cambia. La condizione di un ciclo può invece trovarsi alla fine, garantendo che il ciclo venga eseguito almeno una volta.

```swift
var n = 2
while n < 100 {
    n *= 2
}
print(n)
// Stampa "128".

var m = 2
repeat {
    m *= 2
} while m < 100
print(m)
// Stampa "128".
```

{% hint style="success" %}
**Esperimento:** Cambia la condizione da `m < 100` a `m < 0` per vedere come `while` e `repeat`-`while` si comportano diversamente quando la condizione del ciclo è già falsa.
{% endhint %}

Puoi tenere un indice in un ciclo usando `..<` per creare un intervallo di indici.

```swift
var total = 0
for i in 0..<4 {
    total += i
}
print(total)
// Stampa "6".
```

Usa `..<` per creare un intervallo che omette il suo valore superiore, e usa `...` per creare un intervallo che include entrambi i valori.

## Funzioni e closure <a href="#funzioni-e-closure" id="funzioni-e-closure"></a>

Usa `func` per dichiarare una funzione. Chiama una funzione facendo seguire al suo nome un elenco di argomenti tra parentesi. Usa `->` per separare i nomi e i tipi dei parametri dal tipo di ritorno della funzione.

```swift
func greet(person: String, day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet(person: "Bob", day: "Tuesday")
```

{% hint style="success" %}
**Esperimento:** Rimuovi il parametro `day`. Aggiungi un parametro per includere nel saluto il piatto del giorno.
{% endhint %}

Per impostazione predefinita, le funzioni usano i nomi dei loro parametri come etichette per i loro argomenti. Scrivi un'etichetta dell'argomento personalizzata prima del nome del parametro, oppure scrivi `_` per non usare alcuna etichetta dell'argomento.

```swift
func greet(_ person: String, on day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
```

Usa una tupla per creare un valore composto — per esempio, per restituire più valori da una funzione. Agli elementi di una tupla si può fare riferimento sia per nome sia per numero.

```swift
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
    var min = scores[0]
    var max = scores[0]
    var sum = 0

    for score in scores {
        if score > max {
            max = score
        } else if score < min {
            min = score
        }
        sum += score
    }

    return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
print(statistics.sum)
// Stampa "120".
print(statistics.2)
// Stampa "120".
```

Le funzioni possono essere annidate. Le funzioni annidate hanno accesso alle variabili dichiarate nella funzione esterna. Puoi usare le funzioni annidate per organizzare il codice di una funzione lunga o complessa.

```swift
func returnFifteen() -> Int {
    var y = 10
    func add() {
        y += 5
    }
    add()
    return y
}
returnFifteen()
```

Le funzioni sono un tipo di prima classe. Ciò significa che una funzione può restituire un'altra funzione come suo valore.

```swift
func makeIncrementer() -> ((Int) -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne
}
var increment = makeIncrementer()
increment(7)
```

Una funzione può accettare un'altra funzione come uno dei suoi argomenti.

```swift
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
    for item in list {
        if condition(item) {
            return true
        }
    }
    return false
}
func lessThanTen(number: Int) -> Bool {
    return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)
```

Le funzioni sono in realtà un caso particolare di closure: blocchi di codice che possono essere chiamati in seguito. Il codice in una closure ha accesso a cose come variabili e funzioni che erano disponibili nell'ambito in cui la closure è stata creata, anche se la closure si trova in un ambito diverso quando viene eseguita — ne hai già visto un esempio con le funzioni annidate. Puoi scrivere una closure senza nome racchiudendo il codice tra parentesi graffe (`{}`). Usa `in` per separare gli argomenti e il tipo di ritorno dal corpo.

```swift
numbers.map({ (number: Int) -> Int in
    let result = 3 * number
    return result
})
```

{% hint style="success" %}
**Esperimento:** Riscrivi la closure in modo che restituisca zero per tutti i numeri dispari.
{% endhint %}

Hai diverse possibilità per scrivere le closure in modo più conciso. Quando il tipo di una closure è già noto, come la callback per un delegate, puoi omettere il tipo dei suoi parametri, il suo tipo di ritorno, o entrambi. Le closure con una sola istruzione restituiscono implicitamente il valore della loro unica istruzione.

```swift
let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)
// Stampa "[60, 57, 21, 36]".
```

Puoi riferirti ai parametri per numero anziché per nome — questo approccio è particolarmente utile nelle closure molto brevi. Una closure passata come ultimo argomento di una funzione può comparire immediatamente dopo le parentesi. Quando una closure è l'unico argomento di una funzione, puoi omettere completamente le parentesi.

```swift
let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)
// Stampa "[20, 19, 12, 7]".
```

## Oggetti e classi <a href="#oggetti-e-classi" id="oggetti-e-classi"></a>

Usa `class` seguito dal nome della classe per creare una classe. La dichiarazione di una proprietà in una classe si scrive nello stesso modo della dichiarazione di una costante o di una variabile, tranne per il fatto che si trova nel contesto di una classe. Allo stesso modo, le dichiarazioni di metodi e funzioni si scrivono nello stesso modo.

```swift
class Shape {
    var numberOfSides = 0
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}
```

{% hint style="success" %}
**Esperimento:** Aggiungi una proprietà costante con `let`, e aggiungi un altro metodo che accetti un argomento.
{% endhint %}

Crea un'istanza di una classe mettendo delle parentesi dopo il nome della classe. Usa la sintassi a punto per accedere alle proprietà e ai metodi dell'istanza.

```swift
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
```

A questa versione della classe `Shape` manca qualcosa di importante: un inizializzatore per configurare la classe quando viene creata un'istanza. Usa `init` per crearne uno.

```swift
class NamedShape {
    var numberOfSides: Int = 0
    var name: String

    init(name: String) {
       self.name = name
    }

    func simpleDescription() -> String {
       return "A shape with \(numberOfSides) sides."
    }
}
```

Nota come `self` venga usato per distinguere la proprietà `name` dall'argomento `name` dell'inizializzatore. Gli argomenti dell'inizializzatore vengono passati come in una chiamata di funzione quando crei un'istanza della classe. Ogni proprietà necessita che le sia assegnato un valore — o nella sua dichiarazione (come per `numberOfSides`) o nell'inizializzatore (come per `name`).

Usa `deinit` per creare un deinizializzatore se hai bisogno di eseguire qualche pulizia prima che l'oggetto venga deallocato.

Le sottoclassi includono il nome della loro superclasse dopo il nome della loro classe, separato da due punti. Non c'è alcun obbligo per le classi di essere sottoclassi di una classe radice standard, quindi puoi includere od omettere una superclasse secondo necessità.

I metodi di una sottoclasse che sovrascrivono l'implementazione della superclasse sono contrassegnati con `override` — sovrascrivere un metodo per errore, senza `override`, viene rilevato dal compilatore come un errore. Il compilatore rileva anche i metodi con `override` che in realtà non sovrascrivono alcun metodo della superclasse.

```swift
class Square: NamedShape {
    var sideLength: Double

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
    }

    func area() -> Double {
        return sideLength * sideLength
    }

    override func simpleDescription() -> String {
        return "A square with sides of length \(sideLength)."
    }
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
```

{% hint style="success" %}
**Esperimento:** Crea un'altra sottoclasse di `NamedShape` chiamata `Circle` che accetti un raggio e un nome come argomenti del suo inizializzatore. Implementa un metodo `area()` e un metodo `simpleDescription()` sulla classe `Circle`.
{% endhint %}

Oltre alle semplici proprietà memorizzate, le proprietà possono avere un getter e un setter.

```swift
class EquilateralTriangle: NamedShape {
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }

    var perimeter: Double {
        get {
             return 3.0 * sideLength
        }
        set {
            sideLength = newValue / 3.0
        }
    }

    override func simpleDescription() -> String {
        return "An equilateral triangle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
// Stampa "9.3".
triangle.perimeter = 9.9
print(triangle.sideLength)
// Stampa "3.3000000000000003".
```

Nel setter di `perimeter`, il nuovo valore ha il nome implicito `newValue`. Puoi fornire un nome esplicito tra parentesi dopo `set`.

Nota che l'inizializzatore della classe `EquilateralTriangle` ha tre passaggi diversi:

1. Impostare il valore delle proprietà dichiarate dalla sottoclasse.
2. Chiamare l'inizializzatore della superclasse.
3. Modificare il valore delle proprietà definite dalla superclasse. Qualsiasi ulteriore lavoro di configurazione che usi metodi, getter o setter può essere svolto anche in questo punto.

Se non hai bisogno di calcolare la proprietà ma hai comunque bisogno di fornire del codice da eseguire prima e dopo l'impostazione di un nuovo valore, usa `willSet` e `didSet`. Il codice che fornisci viene eseguito ogni volta che il valore cambia al di fuori di un inizializzatore. Per esempio, la classe seguente garantisce che la lunghezza del lato del suo triangolo sia sempre uguale alla lunghezza del lato del suo quadrato.

```swift
class TriangleAndSquare {
    var triangle: EquilateralTriangle {
        willSet {
            square.sideLength = newValue.sideLength
        }
    }
    var square: Square {
        willSet {
            triangle.sideLength = newValue.sideLength
        }
    }
    init(size: Double, name: String) {
        square = Square(sideLength: size, name: name)
        triangle = EquilateralTriangle(sideLength: size, name: name)
    }
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
print(triangleAndSquare.square.sideLength)
// Stampa "10.0".
print(triangleAndSquare.triangle.sideLength)
// Stampa "10.0".
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)
// Stampa "50.0".
```

Quando lavori con valori opzionali, puoi scrivere `?` prima di operazioni come metodi, proprietà e subscript. Se il valore prima di `?` è `nil`, tutto ciò che segue `?` viene ignorato e il valore dell'intera espressione è `nil`. Altrimenti, viene fatto l'unwrapping del valore opzionale, e tutto ciò che segue `?` agisce sul valore estratto. In entrambi i casi, il valore dell'intera espressione è un valore opzionale.

```swift
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
```

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

Usa `enum` per creare un'enumerazione. Come le classi e tutti gli altri tipi con nome, le enumerazioni possono avere metodi associati.

```swift
enum Rank: Int {
    case ace = 1
    case two, three, four, five, six, seven, eight, nine, ten
    case jack, queen, king

    func simpleDescription() -> String {
        switch self {
        case .ace:
            return "ace"
        case .jack:
            return "jack"
        case .queen:
            return "queen"
        case .king:
            return "king"
        default:
            return String(self.rawValue)
        }
    }
}
let ace = Rank.ace
let aceRawValue = ace.rawValue
```

{% hint style="success" %}
**Esperimento:** Scrivi una funzione che confronti due valori `Rank` confrontando i loro valori grezzi.
{% endhint %}

Per impostazione predefinita, Swift assegna i valori grezzi partendo da zero e incrementandoli di uno ogni volta, ma puoi cambiare questo comportamento specificando esplicitamente dei valori. Nell'esempio qui sopra, a `Ace` viene dato esplicitamente un valore grezzo di `1`, e il resto dei valori grezzi viene assegnato in ordine. Puoi anche usare stringhe o numeri in virgola mobile come tipo grezzo di un'enumerazione. Usa la proprietà `rawValue` per accedere al valore grezzo di un caso di enumerazione.

Usa l'inizializzatore `init?(rawValue:)` per creare un'istanza di un'enumerazione a partire da un valore grezzo. Restituisce il caso dell'enumerazione che corrisponde al valore grezzo oppure `nil` se non c'è alcun `Rank` corrispondente.

```swift
if let convertedRank = Rank(rawValue: 3) {
    let threeDescription = convertedRank.simpleDescription()
}
```

I valori dei casi di un'enumerazione sono valori veri e propri, non semplicemente un altro modo di scrivere i loro valori grezzi. Anzi, nei casi in cui non esiste un valore grezzo significativo, non devi fornirne uno.

```swift
enum Suit {
    case spades, hearts, diamonds, clubs

    func simpleDescription() -> String {
        switch self {
        case .spades:
            return "spades"
        case .hearts:
            return "hearts"
        case .diamonds:
            return "diamonds"
        case .clubs:
            return "clubs"
        }
    }
}
let hearts = Suit.hearts
let heartsDescription = hearts.simpleDescription()
```

{% hint style="success" %}
**Esperimento:** Aggiungi a `Suit` un metodo `color()` che restituisca "black" per picche e fiori, e restituisca "red" per cuori e quadri.
{% endhint %}

Nota i due modi in cui si fa riferimento al caso `hearts` dell'enumerazione nel codice qui sopra: quando si assegna un valore alla costante `hearts`, si fa riferimento al caso dell'enumerazione `Suit.hearts` con il suo nome completo perché per la costante non è specificato un tipo esplicito. All'interno dello switch, si fa riferimento al caso dell'enumerazione con la forma abbreviata `.hearts` perché è già noto che il valore di `self` è un seme. Puoi usare la forma abbreviata ogni volta che il tipo del valore è già noto.

Se un'enumerazione ha valori grezzi, quei valori sono determinati come parte della dichiarazione, il che significa che ogni istanza di un particolare caso di enumerazione ha sempre lo stesso valore grezzo. Un'altra possibilità per i casi di enumerazione è avere valori associati al caso — questi valori sono determinati quando crei l'istanza, e possono essere diversi per ciascuna istanza di un caso di enumerazione. Puoi pensare ai valori associati come se si comportassero come proprietà memorizzate dell'istanza del caso di enumerazione. Per esempio, considera il caso della richiesta a un server degli orari di alba e tramonto. Il server risponde con le informazioni richieste, oppure risponde con una descrizione di ciò che è andato storto.

```swift
enum ServerResponse {
    case result(String, String)
    case failure(String)
}

let success = ServerResponse.result("6:00 am", "8:09 pm")
let failure = ServerResponse.failure("Out of cheese.")

switch success {
case let .result(sunrise, sunset):
    print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
    print("Failure...  \(message)")
}
// Stampa "Sunrise is at 6:00 am and sunset is at 8:09 pm."
```

{% hint style="success" %}
**Esperimento:** Aggiungi un terzo caso a `ServerResponse` e allo switch.
{% endhint %}

Nota come gli orari di alba e tramonto vengano estratti dal valore `ServerResponse` come parte del confronto del valore con i casi dello switch.

Usa `struct` per creare una struttura. Le strutture supportano molti degli stessi comportamenti delle classi, compresi metodi e inizializzatori. Una delle differenze più importanti tra strutture e classi è che le strutture vengono sempre copiate quando vengono passate da una parte all'altra nel tuo codice, mentre le classi vengono passate per riferimento.

```swift
struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}
let threeOfSpades = Card(rank: .three, suit: .spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
```

{% hint style="success" %}
**Esperimento:** Scrivi una funzione che restituisca un array contenente un mazzo completo di carte, con una carta per ogni combinazione di valore e seme.
{% endhint %}

## Concorrenza <a href="#concorrenza" id="concorrenza"></a>

Usa `async` per contrassegnare una funzione che viene eseguita in modo asincrono.

```swift
func fetchUserID(from server: String) async -> Int {
    if server == "primary" {
        return 97
    }
    return 501
}
```

Contrassegni una chiamata a una funzione asincrona scrivendo `await` davanti a essa.

```swift
func fetchUsername(from server: String) async -> String {
    let userID = await fetchUserID(from: server)
    if userID == 501 {
        return "John Appleseed"
    }
    return "Guest"
}
```

Usa `async let` per chiamare una funzione asincrona, lasciandola eseguire in parallelo con altro codice asincrono. Quando usi il valore che restituisce, scrivi `await`.

```swift
func connectUser(to server: String) async {
    async let userID = fetchUserID(from: server)
    async let username = fetchUsername(from: server)
    let greeting = await "Hello \(username), user ID \(userID)"
    print(greeting)
}
```

Usa `Task` per chiamare funzioni asincrone da codice sincrono, senza attendere che restituiscano un risultato.

```swift
Task {
    await connectUser(to: "primary")
}
// Stampa "Hello Guest, user ID 97".
```

Usa i gruppi di task per strutturare il codice concorrente.

```swift
let userIDs = await withTaskGroup(of: Int.self) { group in
    for server in ["primary", "secondary", "development"] {
        group.addTask {
            return await fetchUserID(from: server)
        }
    }

    var results: [Int] = []
    for await result in group {
        results.append(result)
    }
    return results
}
```

Gli actor sono simili alle classi, tranne per il fatto che garantiscono che diverse funzioni asincrone possano interagire in modo sicuro con un'istanza dello stesso actor nello stesso momento.

```swift
actor ServerConnection {
    var server: String = "primary"
    private var activeUsers: [Int] = []
    func connect() async -> Int {
        let userID = await fetchUserID(from: server)
        // ... comunica con il server ...
        activeUsers.append(userID)
        return userID
    }
}
```

Quando chiami un metodo su un actor o accedi a una delle sue proprietà, contrassegni quel codice con `await` per indicare che potrebbe dover attendere che termini altro codice già in esecuzione sull'actor.

```swift
let server = ServerConnection()
let userID = await server.connect()
```

## Protocolli ed estensioni <a href="#protocolli-ed-estensioni" id="protocolli-ed-estensioni"></a>

Usa `protocol` per dichiarare un protocollo.

```swift
protocol ExampleProtocol {
     var simpleDescription: String { get }
     mutating func adjust()
}
```

Classi, enumerazioni e strutture possono tutte adottare protocolli.

```swift
class SimpleClass: ExampleProtocol {
     var simpleDescription: String = "A very simple class."
     var anotherProperty: Int = 69105
     func adjust() {
          simpleDescription += "  Now 100% adjusted."
     }
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription

struct SimpleStructure: ExampleProtocol {
     var simpleDescription: String = "A simple structure"
     mutating func adjust() {
          simpleDescription += " (adjusted)"
     }
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
```

{% hint style="success" %}
**Esperimento:** Aggiungi un altro requisito a `ExampleProtocol`. Quali modifiche devi apportare a `SimpleClass` e `SimpleStructure` affinché siano ancora conformi al protocollo?
{% endhint %}

Nota l'uso della parola chiave `mutating` nella dichiarazione di `SimpleStructure` per contrassegnare un metodo che modifica la struttura. La dichiarazione di `SimpleClass` non ha bisogno che alcuno dei suoi metodi sia contrassegnato come mutating perché i metodi di una classe possono sempre modificare la classe.

Usa `extension` per aggiungere funzionalità a un tipo esistente, come nuovi metodi e proprietà calcolate. Puoi usare un'estensione per aggiungere la conformità a un protocollo a un tipo dichiarato altrove, o persino a un tipo che hai importato da una libreria o da un framework.

```swift
extension Int: ExampleProtocol {
    var simpleDescription: String {
        return "The number \(self)"
    }
    mutating func adjust() {
        self += 42
    }
 }
print(7.simpleDescription)
// Stampa "The number 7".
```

{% hint style="success" %}
**Esperimento:** Scrivi un'estensione per il tipo `Double` che aggiunga una proprietà `absoluteValue`.
{% endhint %}

Puoi usare il nome di un protocollo proprio come qualsiasi altro tipo con nome — per esempio, per creare una collezione di oggetti che hanno tipi diversi ma che sono tutti conformi a un unico protocollo. Quando lavori con valori il cui tipo è un tipo protocollo boxed, i metodi al di fuori della definizione del protocollo non sono disponibili.

```swift
let protocolValue: any ExampleProtocol = a
print(protocolValue.simpleDescription)
// Stampa "A very simple class.  Now 100% adjusted."
// print(protocolValue.anotherProperty)  // Togli il commento per vedere l'errore
```

Anche se la variabile `protocolValue` ha un tipo in fase di esecuzione `SimpleClass`, il compilatore la tratta come del tipo dato `ExampleProtocol`. Ciò significa che non puoi accedere accidentalmente a metodi o proprietà che la classe implementa in aggiunta alla sua conformità al protocollo.

## Gestione degli errori <a href="#gestione-degli-errori" id="gestione-degli-errori"></a>

Rappresenti gli errori usando un qualsiasi tipo che adotti il protocollo `Error`.

```swift
enum PrinterError: Error {
    case outOfPaper
    case noToner
    case onFire
}
```

Usa `throw` per lanciare un errore e `throws` per contrassegnare una funzione che può lanciare un errore. Se lanci un errore in una funzione, la funzione restituisce immediatamente il controllo e il codice che ha chiamato la funzione gestisce l'errore.

```swift
func send(job: Int, toPrinter printerName: String) throws -> String {
    if printerName == "Never Has Toner" {
        throw PrinterError.noToner
    }
    return "Job sent"
}
```

Ci sono diversi modi per gestire gli errori. Un modo è usare `do`-`catch`. All'interno del blocco `do`, contrassegni il codice che può lanciare un errore scrivendo `try` davanti a esso. All'interno del blocco `catch`, all'errore viene dato automaticamente il nome `error` a meno che tu non gli dia un nome diverso.

```swift
do {
    let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")
    print(printerResponse)
} catch {
    print(error)
}
// Stampa "Job sent".
```

{% hint style="success" %}
**Esperimento:** Cambia il nome della stampante in `"Never Has Toner"`, in modo che la funzione `send(job:toPrinter:)` lanci un errore.
{% endhint %}

Puoi fornire più blocchi `catch` che gestiscono errori specifici. Scrivi un pattern dopo `catch` proprio come fai dopo `case` in uno switch.

```swift
do {
    let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")
    print(printerResponse)
} catch PrinterError.onFire {
    print("I'll just put this over here, with the rest of the fire.")
} catch let printerError as PrinterError {
    print("Printer error: \(printerError).")
} catch {
    print(error)
}
// Stampa "Job sent".
```

{% hint style="success" %}
**Esperimento:** Aggiungi del codice per lanciare un errore all'interno del blocco `do`. Che tipo di errore devi lanciare affinché l'errore venga gestito dal primo blocco `catch`? E per il secondo e il terzo blocco?
{% endhint %}

Un altro modo per gestire gli errori è usare `try?` per convertire il risultato in un opzionale. Se la funzione lancia un errore, l'errore specifico viene scartato e il risultato è `nil`. Altrimenti, il risultato è un opzionale contenente il valore restituito dalla funzione.

```swift
let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")
```

Usa `defer` per scrivere un blocco di codice che viene eseguito dopo tutto l'altro codice della funzione, subito prima che la funzione restituisca il controllo. Il codice viene eseguito indipendentemente dal fatto che la funzione lanci un errore. Puoi usare `defer` per scrivere codice di configurazione e codice di pulizia uno accanto all'altro, anche se devono essere eseguiti in momenti diversi.

```swift
var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs", "leftovers"]

func fridgeContains(_ food: String) -> Bool {
    fridgeIsOpen = true
    defer {
        fridgeIsOpen = false
    }

    let result = fridgeContent.contains(food)
    return result
}
if fridgeContains("banana") {
    print("Found a banana")
}
print(fridgeIsOpen)
// Stampa "false".
```

## Generici <a href="#generici" id="generici"></a>

Scrivi un nome tra parentesi angolari per creare una funzione o un tipo generico.

```swift
func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
    var result: [Item] = []
    for _ in 0..<numberOfTimes {
         result.append(item)
    }
    return result
}
makeArray(repeating: "knock", numberOfTimes: 4)
```

Puoi creare forme generiche di funzioni e metodi, così come di classi, enumerazioni e strutture.

```swift
// Reimplementa il tipo opzionale della libreria standard di Swift
enum OptionalValue<Wrapped> {
    case none
    case some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .none
possibleInteger = .some(100)
```

Usa `where` subito prima del corpo per specificare un elenco di requisiti — per esempio, per richiedere che il tipo implementi un protocollo, per richiedere che due tipi siano uguali, o per richiedere che una classe abbia una particolare superclasse.

```swift
func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
    where T.Element: Equatable, T.Element == U.Element
{
    for lhsItem in lhs {
        for rhsItem in rhs {
            if lhsItem == rhsItem {
                return true
            }
        }
    }
   return false
}
anyCommonElements([1, 2, 3], [3])
```

{% hint style="success" %}
**Esperimento:** Modifica la funzione `anyCommonElements(_:_:)` per creare una funzione che restituisca un array degli elementi che due sequenze qualsiasi hanno in comune.
{% endhint %}

Scrivere `<T: Equatable>` equivale a scrivere `<T> ... where T: Equatable`.
