> 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/riferimento-del-linguaggio/dichiarazioni.md).

# Dichiarazioni (Declarations)

Introduci tipi, operatori, variabili e altri nomi e costrutti.

Una *dichiarazione* introduce un nuovo nome o costrutto nel tuo programma. Per esempio, usi le dichiarazioni per introdurre funzioni e metodi, per introdurre variabili e costanti, e per definire tipi enumerazione, struttura, classe e protocollo. Puoi anche usare una dichiarazione per estendere il comportamento di un tipo con nome esistente e per importare nel tuo programma simboli dichiarati altrove.

In Swift, la maggior parte delle dichiarazioni sono anche definizioni, nel senso che vengono implementate o inizializzate nello stesso momento in cui vengono dichiarate. Detto questo, poiché i protocolli non implementano i loro membri, la maggior parte dei membri dei protocolli sono solo dichiarazioni. Per comodità e poiché la distinzione non è così importante in Swift, il termine *dichiarazione* copre sia le dichiarazioni sia le definizioni.

{% hint style="info" %}
**Grammatica di una dichiarazione:**

*declaration* → *import-declaration*\
*declaration* → *constant-declaration*\
*declaration* → *variable-declaration*\
*declaration* → *typealias-declaration*\
*declaration* → *function-declaration*\
*declaration* → *enum-declaration*\
*declaration* → *struct-declaration*\
*declaration* → *class-declaration*\
*declaration* → *actor-declaration*\
*declaration* → *protocol-declaration*\
*declaration* → *initializer-declaration*\
*declaration* → *deinitializer-declaration*\
*declaration* → *extension-declaration*\
*declaration* → *subscript-declaration*\
*declaration* → *macro-declaration*\
*declaration* → *operator-declaration*\
*declaration* → *precedence-group-declaration*
{% endhint %}

## Codice di primo livello <a href="#codice-di-primo-livello" id="codice-di-primo-livello"></a>

Il codice di primo livello in un file sorgente Swift è costituito da zero o più istruzioni, dichiarazioni ed espressioni. Per impostazione predefinita, le variabili, le costanti e le altre dichiarazioni con nome dichiarate al primo livello di un file sorgente sono accessibili al codice in ogni file sorgente che fa parte dello stesso modulo. Puoi modificare questo comportamento predefinito contrassegnando la dichiarazione con un modificatore di livello di accesso, come descritto in [Livelli di controllo degli accessi](/riferimento-del-linguaggio/dichiarazioni.md#livelli-di-controllo-degli-accessi).

Esistono due tipi di codice di primo livello: le dichiarazioni di primo livello e il codice eseguibile di primo livello. Le dichiarazioni di primo livello sono costituite solo da dichiarazioni e sono ammesse in tutti i file sorgente Swift. Il codice eseguibile di primo livello contiene istruzioni ed espressioni, non solo dichiarazioni, ed è ammesso solo come punto di ingresso di primo livello del programma.

Il codice Swift che compili per creare un eseguibile può contenere al massimo uno dei seguenti approcci per contrassegnare il punto di ingresso di primo livello, indipendentemente da come il codice è organizzato in file e moduli: un file che contiene codice eseguibile di primo livello, un file `main.swift`, l'attributo `main`, l'attributo `NSApplicationMain` o l'attributo `UIApplicationMain`.

{% hint style="info" %}
**Grammatica di una dichiarazione di primo livello:**

*top-level-declaration* → *statements?*
{% endhint %}

## Blocchi di codice <a href="#blocchi-di-codice" id="blocchi-di-codice"></a>

Un *blocco di codice* è usato da diverse dichiarazioni e strutture di controllo per raggruppare istruzioni. Ha la forma seguente:

```swift
{
   <#statements#>
}
```

Le *statements* all'interno di un blocco di codice includono dichiarazioni, espressioni e altri tipi di istruzioni, e vengono eseguite nell'ordine in cui compaiono nel codice sorgente.

{% hint style="info" %}
**Grammatica di un blocco di codice:**

*code-block* → **`{`** *statements?* **`}`**
{% endhint %}

## Dichiarazione di importazione <a href="#dichiarazione-di-importazione" id="dichiarazione-di-importazione"></a>

Una *dichiarazione di importazione* ti permette di accedere a simboli dichiarati al di fuori del file corrente. La forma di base importa l'intero modulo; è costituita dalla parola chiave `import` seguita dal nome di un modulo:

```swift
import <#module#>
```

Fornire maggiori dettagli limita quali simboli vengono importati — puoi specificare un determinato sottomodulo o una determinata dichiarazione all'interno di un modulo o di un sottomodulo. Quando si usa questa forma dettagliata, solo il simbolo importato (e non il modulo che lo dichiara) viene reso disponibile nell'ambito corrente.

```swift
import <#import kind#> <#module#>.<#symbol name#>
import <#module#>.<#submodule#>
```

{% hint style="info" %}
**Grammatica di una dichiarazione di importazione:**

*import-declaration* → *attributes?* **`import`** *import-kind?* *import-path*

*import-kind* → **`typealias`** | **`struct`** | **`class`** | **`enum`** | **`protocol`** | **`let`** | **`var`** | **`func`**\
*import-path* → *identifier* | *identifier* **`.`** *import-path*
{% endhint %}

## Dichiarazione di costante <a href="#dichiarazione-di-costante" id="dichiarazione-di-costante"></a>

Una *dichiarazione di costante* introduce nel tuo programma un valore con nome costante. Le dichiarazioni di costante si dichiarano usando la parola chiave `let` e hanno la forma seguente:

```swift
let <#constant name#>: <#type#> = <#expression#>
```

Una dichiarazione di costante definisce un binding immutabile tra il *constant name* (nome della costante) e il valore dell'*expression* di inizializzazione; dopo che il valore di una costante è stato impostato, non può essere cambiato. Detto questo, se una costante è inizializzata con un oggetto di una classe, l'oggetto stesso può cambiare, ma il binding tra il nome della costante e l'oggetto a cui fa riferimento non può cambiare.

Quando una costante è dichiarata nell'ambito globale, deve essere inizializzata con un valore. Quando una dichiarazione di costante compare nel contesto di una funzione o di un metodo, può essere inizializzata in seguito, purché sia garantito che abbia un valore impostato prima della prima lettura del suo valore. Se il compilatore può dimostrare che il valore della costante non viene mai letto, non è affatto necessario che la costante abbia un valore impostato. Questa analisi è chiamata *inizializzazione definita* — il compilatore dimostra che un valore è sicuramente impostato prima di essere letto.

{% hint style="info" %}
**Nota:** L'inizializzazione definita non può costruire dimostrazioni che richiedono conoscenza del dominio, e la sua capacità di tracciare lo stato attraverso i condizionali ha un limite. Se sei in grado di stabilire che la costante ha sempre un valore impostato, ma il compilatore non può dimostrarlo, prova a semplificare i percorsi del codice che impostano il valore, oppure usa invece una dichiarazione di variabile.
{% endhint %}

Quando una dichiarazione di costante compare nel contesto della dichiarazione di una classe o di una struttura, è considerata una *proprietà costante*. Le dichiarazioni di costante non sono proprietà calcolate e quindi non hanno getter né setter.

Se il *constant name* di una dichiarazione di costante è un pattern tupla, il nome di ciascun elemento della tupla viene vincolato al valore corrispondente nell'*expression* di inizializzazione.

```swift
let (firstNumber, secondNumber) = (10, 42)
```

In questo esempio, `firstNumber` è una costante con nome per il valore `10`, e `secondNumber` è una costante con nome per il valore `42`. Entrambe le costanti possono ora essere usate in modo indipendente:

```swift
print("The first number is \(firstNumber).")
// Stampa "The first number is 10."
print("The second number is \(secondNumber).")
// Stampa "The second number is 42."
```

L'annotazione di tipo (`:` *type*) è facoltativa in una dichiarazione di costante quando il tipo del *constant name* può essere inferito, come descritto in [Inferenza di tipo](/riferimento-del-linguaggio/tipi.md#inferenza-di-tipo).

Per dichiarare una proprietà di tipo costante, contrassegna la dichiarazione con il modificatore di dichiarazione `static`. Una proprietà di tipo costante di una classe è sempre implicitamente final; non puoi contrassegnarla con il modificatore di dichiarazione `class` o `final` per consentire o impedire l'override da parte delle sottoclassi. Le proprietà di tipo sono trattate in [Proprietà di tipo](/guida-al-linguaggio/proprieta.md#proprieta-di-tipo).

Per maggiori informazioni sulle costanti e per indicazioni su quando usarle, vedi [Costanti e variabili](/guida-al-linguaggio/le-basi.md#costanti-e-variabili) e [Proprietà memorizzate](/guida-al-linguaggio/proprieta.md#proprieta-memorizzate).

{% hint style="info" %}
**Grammatica di una dichiarazione di costante:**

*constant-declaration* → *attributes?* *declaration-modifiers?* **`let`** *pattern-initializer-list*

*pattern-initializer-list* → *pattern-initializer* | *pattern-initializer* **`,`** *pattern-initializer-list*\
*pattern-initializer* → *pattern* *initializer?*\
*initializer* → **`=`** *expression*
{% endhint %}

## Dichiarazione di variabile <a href="#dichiarazione-di-variabile" id="dichiarazione-di-variabile"></a>

Una *dichiarazione di variabile* introduce nel tuo programma un valore con nome variabile e si dichiara usando la parola chiave `var`.

Le dichiarazioni di variabile hanno diverse forme che dichiarano diversi tipi di valori con nome mutabili, tra cui variabili e proprietà memorizzate e calcolate, osservatori di variabili memorizzate e di proprietà, e proprietà variabili statiche. La forma appropriata da usare dipende dall'ambito in cui viene dichiarata la variabile e dal tipo di variabile che intendi dichiarare.

{% hint style="info" %}
**Nota:** Puoi dichiarare proprietà anche nel contesto della dichiarazione di un protocollo, come descritto in [Dichiarazione di proprietà di un protocollo](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-proprieta-di-un-protocollo).
{% endhint %}

Puoi eseguire l'override di una proprietà in una sottoclasse contrassegnando la dichiarazione della proprietà della sottoclasse con il modificatore di dichiarazione `override`, come descritto in [Override](/guida-al-linguaggio/ereditarieta.md#override).

### Variabili memorizzate e proprietà variabili memorizzate <a href="#variabili-memorizzate-e-proprieta-variabili-memorizzate" id="variabili-memorizzate-e-proprieta-variabili-memorizzate"></a>

La forma seguente dichiara una variabile memorizzata o una proprietà variabile memorizzata:

```swift
var <#variable name#>: <#type#> = <#expression#>
```

Definisci questa forma di dichiarazione di variabile nell'ambito globale, nell'ambito locale di una funzione, oppure nel contesto della dichiarazione di una classe o di una struttura. Quando una dichiarazione di variabile di questa forma è dichiarata nell'ambito globale o nell'ambito locale di una funzione, viene chiamata *variabile memorizzata*. Quando è dichiarata nel contesto della dichiarazione di una classe o di una struttura, viene chiamata *proprietà variabile memorizzata*.

L'*expression* di inizializzazione non può essere presente nella dichiarazione di un protocollo, ma in tutti gli altri contesti l'*expression* di inizializzazione è facoltativa. Detto questo, se non è presente alcuna *expression* di inizializzazione, la dichiarazione di variabile deve includere un'annotazione di tipo esplicita (`:` *type*).

Come per le dichiarazioni di costante, se una dichiarazione di variabile omette l'*expression* di inizializzazione, la variabile deve avere un valore impostato prima della prima lettura. Sempre come per le dichiarazioni di costante, se il *variable name* (nome della variabile) è un pattern tupla, il nome di ciascun elemento della tupla viene vincolato al valore corrispondente nell'*expression* di inizializzazione.

Come suggeriscono i loro nomi, il valore di una variabile memorizzata o di una proprietà variabile memorizzata è memorizzato in memoria.

### Variabili calcolate e proprietà calcolate <a href="#variabili-calcolate-e-proprieta-calcolate" id="variabili-calcolate-e-proprieta-calcolate"></a>

La forma seguente dichiara una variabile calcolata o una proprietà calcolata:

```swift
var <#variable name#>: <#type#> {
   get {
      <#statements#>
   }
   set(<#setter name#>) {
      <#statements#>
   }
}
```

Definisci questa forma di dichiarazione di variabile nell'ambito globale, nell'ambito locale di una funzione, oppure nel contesto della dichiarazione di una classe, di una struttura, di un'enumerazione o di un'estensione. Quando una dichiarazione di variabile di questa forma è dichiarata nell'ambito globale o nell'ambito locale di una funzione, viene chiamata *variabile calcolata*. Quando è dichiarata nel contesto della dichiarazione di una classe, di una struttura o di un'estensione, viene chiamata *proprietà calcolata*.

Il getter è usato per leggere il valore, e il setter è usato per scrivere il valore. La clausola setter è facoltativa, e quando serve solo un getter, puoi omettere entrambe le clausole e restituire semplicemente il valore richiesto in modo diretto, come descritto in [Proprietà calcolate di sola lettura](/guida-al-linguaggio/proprieta.md#proprieta-calcolate-di-sola-lettura). Ma se fornisci una clausola setter, devi fornire anche una clausola getter.

Il *setter name* (nome del setter) e le parentesi che lo racchiudono sono facoltativi. Se fornisci un nome del setter, viene usato come nome del parametro del setter. Se non fornisci un nome del setter, il nome predefinito del parametro del setter è `newValue`, come descritto in [Dichiarazione abbreviata del setter](/guida-al-linguaggio/proprieta.md#dichiarazione-abbreviata-del-setter).

A differenza dei valori con nome memorizzati e delle proprietà variabili memorizzate, il valore di un valore con nome calcolato o di una proprietà calcolata non è memorizzato in memoria.

Per maggiori informazioni e per vedere esempi di proprietà calcolate, vedi [Proprietà calcolate](/guida-al-linguaggio/proprieta.md#proprieta-calcolate).

### Osservatori di variabili memorizzate e osservatori di proprietà <a href="#osservatori-di-variabili-memorizzate-e-osservatori-di-proprieta" id="osservatori-di-variabili-memorizzate-e-osservatori-di-proprieta"></a>

Puoi anche dichiarare una variabile o una proprietà memorizzata con gli osservatori `willSet` e `didSet`. Una variabile o una proprietà memorizzata dichiarata con osservatori ha la forma seguente:

```swift
var <#variable name#>: <#type#> = <#expression#> {
   willSet(<#setter name#>) {
      <#statements#>
   }
   didSet(<#setter name#>) {
      <#statements#>
   }
}
```

Definisci questa forma di dichiarazione di variabile nell'ambito globale, nell'ambito locale di una funzione, oppure nel contesto della dichiarazione di una classe o di una struttura. Quando una dichiarazione di variabile di questa forma è dichiarata nell'ambito globale o nell'ambito locale di una funzione, gli osservatori vengono chiamati *osservatori di variabili memorizzate*. Quando è dichiarata nel contesto della dichiarazione di una classe o di una struttura, gli osservatori vengono chiamati *osservatori di proprietà*.

Puoi aggiungere osservatori di proprietà a qualsiasi proprietà memorizzata. Puoi anche aggiungere osservatori di proprietà a qualsiasi proprietà ereditata (memorizzata o calcolata) eseguendo l'override della proprietà in una sottoclasse, come descritto in [Override degli osservatori di proprietà](/guida-al-linguaggio/ereditarieta.md#override-degli-osservatori-di-proprieta).

L'*expression* di inizializzazione è facoltativa nel contesto della dichiarazione di una classe o di una struttura, ma obbligatoria altrove. L'annotazione del *type* è facoltativa quando il tipo può essere inferito dall'*expression* di inizializzazione. Questa espressione viene valutata la prima volta che leggi il valore della proprietà. Se sovrascrivi il valore iniziale della proprietà senza leggerlo, questa espressione viene valutata prima della prima scrittura nella proprietà.

Gli osservatori `willSet` e `didSet` forniscono un modo per osservare (e rispondere in modo appropriato) quando il valore di una variabile o di una proprietà viene impostato. Gli osservatori non vengono chiamati quando la variabile o la proprietà viene inizializzata per la prima volta. Vengono invece chiamati solo quando il valore viene impostato al di fuori di un contesto di inizializzazione.

Un osservatore `willSet` viene chiamato subito prima che il valore della variabile o della proprietà venga impostato. Il nuovo valore viene passato all'osservatore `willSet` come costante, e quindi non può essere modificato nell'implementazione della clausola `willSet`. L'osservatore `didSet` viene chiamato subito dopo che il nuovo valore è stato impostato. A differenza dell'osservatore `willSet`, il vecchio valore della variabile o della proprietà viene passato all'osservatore `didSet` nel caso in cui tu debba ancora accedervi. Detto questo, se assegni un valore a una variabile o a una proprietà all'interno della sua stessa clausola dell'osservatore `didSet`, il nuovo valore che assegni sostituirà quello appena impostato e passato all'osservatore `willSet`.

Il *setter name* e le parentesi che lo racchiudono nelle clausole `willSet` e `didSet` sono facoltativi. Se fornisci dei nomi del setter, vengono usati come nomi dei parametri degli osservatori `willSet` e `didSet`. Se non fornisci nomi del setter, il nome predefinito del parametro dell'osservatore `willSet` è `newValue` e il nome predefinito del parametro dell'osservatore `didSet` è `oldValue`.

La clausola `didSet` è facoltativa quando fornisci una clausola `willSet`. Analogamente, la clausola `willSet` è facoltativa quando fornisci una clausola `didSet`.

Se il corpo dell'osservatore `didSet` fa riferimento al vecchio valore, il getter viene chiamato prima dell'osservatore, per rendere disponibile il vecchio valore. Altrimenti, il nuovo valore viene memorizzato senza chiamare il getter della superclasse. L'esempio seguente mostra una proprietà calcolata definita dalla superclasse e sottoposta a override dalle sue sottoclassi per aggiungere un osservatore.

```swift
class Superclass {
    private var xValue = 12
    var x: Int {
        get { print("Getter was called"); return xValue }
        set { print("Setter was called"); xValue = newValue }
    }
}

// Questa sottoclasse non fa riferimento a oldValue nel suo osservatore, quindi il
// getter della superclasse viene chiamato una sola volta per stampare il valore.
class New: Superclass {
    override var x: Int {
        didSet { print("New value \(x)") }
    }
}
let new = New()
new.x = 100
// Stampa "Setter was called".
// Stampa "Getter was called".
// Stampa "New value 100".

// Questa sottoclasse fa riferimento a oldValue nel suo osservatore, quindi il getter
// della superclasse viene chiamato una volta prima del setter, e di nuovo per stampare il valore.
class NewAndOld: Superclass {
    override var x: Int {
        didSet { print("Old value \(oldValue) - new value \(x)") }
    }
}
let newAndOld = NewAndOld()
newAndOld.x = 200
// Stampa "Getter was called".
// Stampa "Setter was called".
// Stampa "Getter was called".
// Stampa "Old value 12 - new value 200".
```

Per maggiori informazioni e per vedere un esempio di come usare gli osservatori di proprietà, vedi [Osservatori di proprietà](/guida-al-linguaggio/proprieta.md#osservatori-di-proprieta).

### Proprietà variabili di tipo <a href="#proprieta-variabili-di-tipo" id="proprieta-variabili-di-tipo"></a>

Per dichiarare una proprietà variabile di tipo, contrassegna la dichiarazione con il modificatore di dichiarazione `static`. Le classi possono invece contrassegnare le proprietà calcolate di tipo con il modificatore di dichiarazione `class` per consentire alle sottoclassi di eseguire l'override dell'implementazione della superclasse. Le proprietà di tipo sono trattate in [Proprietà di tipo](/guida-al-linguaggio/proprieta.md#proprieta-di-tipo).

{% hint style="info" %}
**Grammatica di una dichiarazione di variabile:**

*variable-declaration* → *variable-declaration-head* *pattern-initializer-list*\
*variable-declaration* → *variable-declaration-head* *variable-name* *type-annotation* *code-block*\
*variable-declaration* → *variable-declaration-head* *variable-name* *type-annotation* *getter-setter-block*\
*variable-declaration* → *variable-declaration-head* *variable-name* *type-annotation* *getter-setter-keyword-block*\
*variable-declaration* → *variable-declaration-head* *variable-name* *initializer* *willSet-didSet-block*\
*variable-declaration* → *variable-declaration-head* *variable-name* *type-annotation* *initializer?* *willSet-didSet-block*

*variable-declaration-head* → *attributes?* *declaration-modifiers?* **`var`**\
*variable-name* → *identifier*

*getter-setter-block* → *code-block*\
*getter-setter-block* → **`{`** *getter-clause* *setter-clause?* **`}`**\
*getter-setter-block* → **`{`** *setter-clause* *getter-clause* **`}`**\
*getter-clause* → *attributes?* *mutation-modifier?* **`get`** *code-block*\
*setter-clause* → *attributes?* *mutation-modifier?* **`set`** *setter-name?* *code-block*\
*setter-name* → **`(`** *identifier* **`)`**

*getter-setter-keyword-block* → **`{`** *getter-keyword-clause* *setter-keyword-clause?* **`}`**\
*getter-setter-keyword-block* → **`{`** *setter-keyword-clause* *getter-keyword-clause* **`}`**\
*getter-keyword-clause* → *attributes?* *mutation-modifier?* **`get`**\
*setter-keyword-clause* → *attributes?* *mutation-modifier?* **`set`**

*willSet-didSet-block* → **`{`** *willSet-clause* *didSet-clause?* **`}`**\
*willSet-didSet-block* → **`{`** *didSet-clause* *willSet-clause?* **`}`**\
*willSet-clause* → *attributes?* **`willSet`** *setter-name?* *code-block*\
*didSet-clause* → *attributes?* **`didSet`** *setter-name?* *code-block*
{% endhint %}

## Dichiarazione di alias di tipo <a href="#dichiarazione-di-alias-di-tipo" id="dichiarazione-di-alias-di-tipo"></a>

Una *dichiarazione di alias di tipo* introduce nel tuo programma un alias con nome di un tipo esistente. Le dichiarazioni di alias di tipo si dichiarano usando la parola chiave `typealias` e hanno la forma seguente:

```swift
typealias <#name#> = <#existing type#>
```

Dopo che un alias di tipo è stato dichiarato, il *name* (nome) dell'alias può essere usato al posto dell'*existing type* (tipo esistente) ovunque nel tuo programma. L'*existing type* può essere un tipo con nome o un tipo composto. Gli alias di tipo non creano nuovi tipi; permettono semplicemente a un nome di fare riferimento a un tipo esistente.

Una dichiarazione di alias di tipo può usare parametri generici per dare un nome a un tipo generico esistente. L'alias di tipo può fornire tipi concreti per alcuni o tutti i parametri generici del tipo esistente. Per esempio:

```swift
typealias StringDictionary<Value> = Dictionary<String, Value>

// I dizionari seguenti hanno lo stesso tipo.
var dictionary1: StringDictionary<Int> = [:]
var dictionary2: Dictionary<String, Int> = [:]
```

Quando un alias di tipo è dichiarato con parametri generici, i vincoli su quei parametri devono corrispondere esattamente ai vincoli sui parametri generici del tipo esistente. Per esempio:

```swift
typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>
```

Poiché l'alias di tipo e il tipo esistente possono essere usati in modo intercambiabile, l'alias di tipo non può introdurre vincoli generici aggiuntivi.

Un alias di tipo può inoltrare i parametri generici di un tipo esistente omettendo tutti i parametri generici dalla dichiarazione. Per esempio, l'alias di tipo `Diccionario` dichiarato qui ha gli stessi parametri generici e vincoli di `Dictionary`.

```swift
typealias Diccionario = Dictionary
```

All'interno della dichiarazione di un protocollo, un alias di tipo può dare un nome più breve e più comodo a un tipo usato frequentemente. Per esempio:

```swift
protocol Sequence {
    associatedtype Iterator: IteratorProtocol
    typealias Element = Iterator.Element
}

func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
    // ...
}
```

Senza questo alias di tipo, la funzione `sum` dovrebbe fare riferimento al tipo associato come `T.Iterator.Element` invece di `T.Element`.

Vedi anche [Dichiarazione di tipo associato di un protocollo](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-tipo-associato-di-un-protocollo).

{% hint style="info" %}
**Grammatica di una dichiarazione di alias di tipo:**

*typealias-declaration* → *attributes?* *access-level-modifier?* **`typealias`** *typealias-name* *generic-parameter-clause?* *typealias-assignment*\
*typealias-name* → *identifier*\
*typealias-assignment* → **`=`** *type*
{% endhint %}

## Dichiarazione di funzione <a href="#dichiarazione-di-funzione" id="dichiarazione-di-funzione"></a>

Una *dichiarazione di funzione* introduce una funzione o un metodo nel tuo programma. Una funzione dichiarata nel contesto di una classe, di una struttura, di un'enumerazione o di un protocollo viene chiamata *metodo*. Le dichiarazioni di funzione si dichiarano usando la parola chiave `func` e hanno la forma seguente:

```swift
func <#function name#>(<#parameters#>) -> <#return type#> {
   <#statements#>
}
```

Se la funzione ha un tipo di ritorno `Void`, il tipo di ritorno può essere omesso come segue:

```swift
func <#function name#>(<#parameters#>) {
   <#statements#>
}
```

Il tipo di ciascun parametro deve essere incluso — non può essere inferito. Se scrivi `inout` davanti al tipo di un parametro, il parametro può essere modificato all'interno dell'ambito della funzione. I parametri in-out sono trattati in dettaglio più avanti, in [Parametri in-out](/riferimento-del-linguaggio/dichiarazioni.md#parametri-in-out).

Una dichiarazione di funzione le cui *statements* includono una sola espressione è considerata come una che restituisce il valore di quell'espressione. Questa sintassi di ritorno implicito è presa in considerazione solo quando il tipo dell'espressione e il tipo di ritorno della funzione non sono `Void` e non sono un'enumerazione come `Never` che non ha alcun caso.

Le funzioni possono restituire più valori usando un tipo tupla come tipo di ritorno della funzione.

La definizione di una funzione può comparire all'interno della dichiarazione di un'altra funzione. Questo tipo di funzione è noto come *funzione annidata*.

Una funzione annidata è non-escaping se cattura un valore che è garantito non effettuare mai l'escape — come un parametro in-out — oppure se viene passata come argomento di funzione non-escaping. Altrimenti, la funzione annidata è una funzione escaping.

Per una trattazione delle funzioni annidate, vedi [Funzioni annidate](/guida-al-linguaggio/funzioni.md#funzioni-annidate).

### Nomi dei parametri <a href="#nomi-dei-parametri" id="nomi-dei-parametri"></a>

I parametri di una funzione sono un elenco separato da virgole in cui ciascun parametro ha una tra diverse forme. L'ordine degli argomenti in una chiamata di funzione deve corrispondere all'ordine dei parametri nella dichiarazione della funzione. La voce più semplice in un elenco di parametri ha la forma seguente:

```swift
<#parameter name#>: <#parameter type#>
```

Un parametro ha un nome, che viene usato all'interno del corpo della funzione, e un'etichetta dell'argomento, che viene usata quando si chiama la funzione o il metodo. Per impostazione predefinita, i nomi dei parametri sono usati anche come etichette dell'argomento. Per esempio:

```swift
func f(x: Int, y: Int) -> Int { return x + y }
f(x: 1, y: 2) // sia x sia y hanno un'etichetta
```

Puoi modificare il comportamento predefinito delle etichette dell'argomento con una delle forme seguenti:

```swift
<#argument label#> <#parameter name#>: <#parameter type#>
_ <#parameter name#>: <#parameter type#>
```

Un nome prima del nome del parametro dà al parametro un'etichetta dell'argomento esplicita, che può essere diversa dal nome del parametro. L'argomento corrispondente deve usare l'etichetta dell'argomento data nelle chiamate di funzione o di metodo.

Un trattino basso (`_`) prima del nome di un parametro sopprime l'etichetta dell'argomento. L'argomento corrispondente non deve avere alcuna etichetta nelle chiamate di funzione o di metodo.

```swift
func repeatGreeting(_ greeting: String, count n: Int) { /* Saluta n volte */ }
repeatGreeting("Hello, world!", count: 2) //  count ha un'etichetta, greeting no
```

### Modificatori dei parametri <a href="#modificatori-dei-parametri" id="modificatori-dei-parametri"></a>

Un *modificatore di parametro* cambia il modo in cui un argomento viene passato alla funzione.

```swift
<#argument label#> <#parameter name#>: <#parameter modifier#> <#parameter type#>
```

Per usare un modificatore di parametro, scrivi `inout`, `borrowing` o `consuming` prima del tipo dell'argomento.

```swift
func someFunction(a: inout A, b: consuming B, c: C) { ... }
```

#### Parametri in-out <a href="#parametri-in-out" id="parametri-in-out"></a>

Per impostazione predefinita, in Swift gli argomenti delle funzioni vengono passati per valore: qualsiasi modifica apportata all'interno della funzione non è visibile al chiamante. Per creare invece un parametro in-out, applica il modificatore di parametro `inout`.

```swift
func someFunction(a: inout Int) {
    a += 1
}
```

Quando chiami una funzione che include parametri in-out, l'argomento in-out deve essere preceduto da una e commerciale (`&`) per indicare che la chiamata di funzione può cambiare il valore dell'argomento.

```swift
var x = 7
someFunction(a: &x)
print(x)  // Stampa "8"
```

I parametri in-out vengono passati come segue:

1. Quando la funzione viene chiamata, il valore dell'argomento viene copiato.
2. Nel corpo della funzione, la copia viene modificata.
3. Quando la funzione restituisce, il valore della copia viene assegnato all'argomento originale.

Questo comportamento è noto come *copy-in copy-out* o *chiamata per valore-risultato*. Per esempio, quando una proprietà calcolata o una proprietà con osservatori viene passata come parametro in-out, il suo getter viene chiamato come parte della chiamata di funzione e il suo setter viene chiamato come parte del ritorno dalla funzione.

Come ottimizzazione, quando l'argomento è un valore memorizzato a un indirizzo fisico in memoria, la stessa posizione di memoria viene usata sia all'interno sia all'esterno del corpo della funzione. Il comportamento ottimizzato è noto come *chiamata per riferimento*; soddisfa tutti i requisiti del modello copy-in copy-out eliminando al contempo il costo della copia. Scrivi il tuo codice usando il modello dato dal copy-in copy-out, senza dipendere dall'ottimizzazione della chiamata per riferimento, così che si comporti correttamente con o senza l'ottimizzazione.

All'interno di una funzione, non accedere a un valore passato come argomento in-out, anche se il valore originale è disponibile nell'ambito corrente. Accedere all'originale costituisce un accesso simultaneo al valore, il che viola l'esclusività della memoria.

```swift
var someValue: Int
func someFunction(a: inout Int) {
    a += someValue
}

// Errore: questo causa una violazione di esclusività in fase di esecuzione
someFunction(a: &someValue)
```

Per lo stesso motivo, non puoi passare lo stesso valore a più parametri in-out.

```swift
var someValue: Int
func someFunction(a: inout Int, b: inout Int) {
    a += b
    b += 1
}

// Errore: non è possibile passare lo stesso valore a più parametri in-out
someFunction(a: &someValue, b: &someValue)
```

Per maggiori informazioni sulla sicurezza della memoria e sull'esclusività della memoria, vedi [Sicurezza della memoria](/guida-al-linguaggio/sicurezza-della-memoria.md).

Una closure o una funzione annidata che cattura un parametro in-out deve essere non-escaping. Se devi catturare un parametro in-out senza modificarlo, usa una lista di cattura per catturare esplicitamente il parametro in modo immutabile.

```swift
func someFunction(a: inout Int) -> () -> Int {
    return { [a] in return a + 1 }
}
```

Se devi catturare e modificare un parametro in-out, usa una copia locale esplicita, come nel codice multithread che garantisce che tutte le modifiche siano terminate prima che la funzione restituisca.

```swift
func multithreadedFunction(queue: DispatchQueue, x: inout Int) {
    // Crea una copia locale e ricopiala manualmente.
    var localX = x
    defer { x = localX }

    // Opera su localX in modo asincrono, poi attendi prima di restituire.
    queue.async { someMutatingOperation(&localX) }
    queue.sync {}
}
```

Per ulteriori approfondimenti ed esempi sui parametri in-out, vedi [Parametri in-out](/guida-al-linguaggio/funzioni.md#parametri-in-out).

#### Parametri borrowing e consuming <a href="#parametri-borrowing-e-consuming" id="parametri-borrowing-e-consuming"></a>

Per impostazione predefinita, Swift usa un insieme di regole per gestire automaticamente il ciclo di vita degli oggetti attraverso le chiamate di funzione, copiando i valori quando necessario. Le regole predefinite sono progettate per ridurre al minimo il costo nella maggior parte dei casi — se vuoi un controllo più specifico, puoi applicare il modificatore di parametro `borrowing` o `consuming`. In questo caso, usa `copy` per contrassegnare esplicitamente le operazioni di copia. Inoltre, i valori di un tipo non copiabile devono essere passati come borrowing o come consuming.

Indipendentemente dal fatto che tu usi le regole predefinite, Swift garantisce che il ciclo di vita e la proprietà degli oggetti siano gestiti correttamente in tutti i casi. Questi modificatori di parametro influiscono solo sull'efficienza relativa di particolari modelli d'uso, non sulla correttezza.

Il modificatore `borrowing` indica che la funzione non conserva il valore del parametro. In questo caso, il chiamante mantiene la proprietà dell'oggetto e la responsabilità del ciclo di vita dell'oggetto. Usare `borrowing` riduce al minimo il costo quando la funzione usa l'oggetto solo in modo transitorio.

```swift
// `isLessThan` non conserva nessuno dei due argomenti
func isLessThan(lhs: borrowing A, rhs: borrowing A) -> Bool {
    ...
}
```

Se la funzione deve conservare il valore del parametro per esempio, memorizzandolo in una variabile globale — usi `copy` per copiare esplicitamente quel valore.

```swift
// Come sopra, ma questa `isLessThan` vuole anche registrare il valore più piccolo
func isLessThan(lhs: borrowing A, rhs: borrowing A) -> Bool {
    if lhs < storedValue {
        storedValue = copy lhs
    } else if rhs < storedValue {
        storedValue = copy rhs
    }
    return lhs < rhs
}
```

Al contrario, il modificatore di parametro `consuming` indica che la funzione assume la proprietà del valore, accettando la responsabilità di memorizzarlo o distruggerlo prima che la funzione restituisca.

```swift
// `store` conserva il suo argomento, quindi contrassegnalo come `consuming`
func store(a: consuming A) {
    someGlobalVariable = a
}
```

Usare `consuming` riduce al minimo il costo quando il chiamante non ha più bisogno di usare l'oggetto dopo la chiamata di funzione.

```swift
// Di solito, questa è l'ultima cosa che fai con un valore
store(a: value)
```

Se continui a usare un oggetto copiabile dopo la chiamata di funzione, il compilatore crea automaticamente una copia di quell'oggetto prima della chiamata di funzione.

```swift
// Il compilatore inserisce qui una copia implicita
store(a: someValue)  // Questa funzione consuma someValue
print(someValue)  // Questa usa la copia di someValue
```

A differenza di `inout`, né i parametri `borrowing` né i parametri `consuming` richiedono alcuna notazione speciale quando chiami la funzione:

```swift
func someFunction(a: borrowing A, b: consuming B) { ... }

someFunction(a: someA, b: someB)
```

L'uso esplicito di `borrowing` o di `consuming` indica la tua intenzione di controllare più rigorosamente il costo della gestione della proprietà in fase di esecuzione. Poiché le copie possono causare operazioni inattese di gestione della proprietà in fase di esecuzione, i parametri contrassegnati con uno di questi modificatori non possono essere copiati a meno che tu non usi una parola chiave `copy` esplicita:

```swift
func borrowingFunction1(a: borrowing A) {
    // Errore: non è possibile copiare implicitamente a
    // Questa assegnazione richiede una copia perché
    // `a` è solo preso in prestito dal chiamante.
    someGlobalVariable = a
}

func borrowingFunction2(a: borrowing A) {
    // OK: la copia esplicita funziona
    someGlobalVariable = copy a
}

func consumingFunction1(a: consuming A) {
    // Errore: non è possibile copiare implicitamente a
    // Questa assegnazione richiede una copia a causa
    // del `print` seguente
    someGlobalVariable = a
    print(a)
}

func consumingFunction2(a: consuming A) {
    // OK: la copia esplicita funziona in ogni caso
    someGlobalVariable = copy a
    print(a)
}

func consumingFunction3(a: consuming A) {
    // OK: qui non serve alcuna copia perché questo è l'ultimo uso
    someGlobalVariable = a
}
```

### Tipi speciali di parametri <a href="#tipi-speciali-di-parametri" id="tipi-speciali-di-parametri"></a>

I parametri possono essere ignorati, accettare un numero variabile di valori e fornire valori predefiniti usando le forme seguenti:

```swift
_ : <#parameter type#>
<#parameter name#>: <#parameter type#>...
<#parameter name#>: <#parameter type#> = <#default argument value#>
```

Un parametro trattino basso (`_`) è esplicitamente ignorato e non è accessibile all'interno del corpo della funzione.

Un parametro con il nome di un tipo di base seguito immediatamente da tre punti (`...`) è considerato un parametro variadico. Un parametro che segue immediatamente un parametro variadico deve avere un'etichetta dell'argomento. Una funzione può avere più parametri variadici. Un parametro variadico viene trattato come un array che contiene elementi del tipo di base indicato. Per esempio, il parametro variadico `Int...` viene trattato come `[Int]`. Per un esempio che usa un parametro variadico, vedi [Parametri variadici](/guida-al-linguaggio/funzioni.md#parametri-variadici).

Un parametro con un segno di uguale (`=`) e un'espressione dopo il suo tipo è considerato come avente per valore predefinito l'espressione data. L'espressione data viene valutata quando la funzione viene chiamata. Se il parametro viene omesso quando si chiama la funzione, viene usato invece il valore predefinito.

```swift
func f(x: Int = 42) -> Int { return x }
f()       // Valido, usa il valore predefinito
f(x: 7)   // Valido, usa il valore fornito
f(7)      // Non valido, manca l'etichetta dell'argomento
```

### Tipi speciali di metodi <a href="#tipi-speciali-di-metodi" id="tipi-speciali-di-metodi"></a>

I metodi di un'enumerazione o di una struttura che modificano `self` devono essere contrassegnati con il modificatore di dichiarazione `mutating`.

I metodi che eseguono l'override di un metodo della superclasse devono essere contrassegnati con il modificatore di dichiarazione `override`. È un errore in fase di compilazione eseguire l'override di un metodo senza il modificatore `override` o usare il modificatore `override` su un metodo che non esegue l'override di un metodo della superclasse.

I metodi associati a un tipo anziché a un'istanza di un tipo devono essere contrassegnati con il modificatore di dichiarazione `static` per le enumerazioni e le strutture, oppure con il modificatore di dichiarazione `static` o `class` per le classi. Un metodo di tipo di una classe contrassegnato con il modificatore di dichiarazione `class` può essere sottoposto a override dall'implementazione di una sottoclasse; un metodo di tipo di una classe contrassegnato con `class final` o `static` non può essere sottoposto a override.

### Metodi con nomi speciali <a href="#metodi-con-nomi-speciali" id="metodi-con-nomi-speciali"></a>

Diversi metodi che hanno nomi speciali abilitano lo zucchero sintattico per la sintassi di chiamata di funzione. Se un tipo definisce uno di questi metodi, le istanze del tipo possono essere usate nella sintassi di chiamata di funzione. La chiamata di funzione è interpretata come una chiamata a uno dei metodi con nome speciale su quell'istanza.

Un tipo classe, struttura o enumerazione può supportare la sintassi di chiamata di funzione definendo un metodo `dynamicallyCall(withArguments:)` o un metodo `dynamicallyCall(withKeywordArguments:)`, come descritto in [dynamicCallable](/riferimento-del-linguaggio/attributi.md#dynamiccallable), oppure definendo un metodo call-as-function, come descritto di seguito. Se il tipo definisce sia un metodo call-as-function sia uno dei metodi usati dall'attributo `dynamicCallable`, il compilatore dà la preferenza al metodo call-as-function nelle circostanze in cui potrebbe essere usato l'uno o l'altro metodo.

Il nome di un metodo call-as-function è `callAsFunction()`, oppure un altro nome che inizia con `callAsFunction(` e aggiunge argomenti con o senza etichetta — per esempio, anche `callAsFunction(_:_:)` e `callAsFunction(something:)` sono nomi validi di metodi call-as-function.

Le chiamate di funzione seguenti sono equivalenti:

```swift
struct CallableStruct {
    var value: Int
    func callAsFunction(_ number: Int, scale: Int) {
        print(scale * (number + value))
    }
}
let callable = CallableStruct(value: 100)
callable(4, scale: 2)
callable.callAsFunction(4, scale: 2)
// Entrambe le chiamate di funzione stampano 208.
```

I metodi call-as-function e i metodi dell'attributo `dynamicCallable` offrono compromessi diversi tra quante informazioni codifichi nel sistema dei tipi e quanto comportamento dinamico è possibile in fase di esecuzione. Quando dichiari un metodo call-as-function, specifichi il numero di argomenti, e il tipo e l'etichetta di ciascun argomento. I metodi dell'attributo `dynamicCallable` specificano solo il tipo usato per contenere l'array di argomenti.

Definire un metodo call-as-function, o un metodo dell'attributo `dynamicCallable`, non ti permette di usare un'istanza di quel tipo come se fosse una funzione in un contesto diverso da un'espressione di chiamata di funzione. Per esempio:

```swift
let someFunction1: (Int, Int) -> Void = callable(_:scale:)  // Errore
let someFunction2: (Int, Int) -> Void = callable.callAsFunction(_:scale:)
```

Il subscript `subscript(dynamicMember:)` abilita lo zucchero sintattico per la ricerca dei membri, come descritto in [dynamicMemberLookup](/riferimento-del-linguaggio/attributi.md#dynamicmemberlookup).

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

Le funzioni e i metodi che possono lanciare un errore devono essere contrassegnati con la parola chiave `throws`. Queste funzioni e questi metodi sono noti come *funzioni throwing* e *metodi throwing*. Hanno la forma seguente:

```swift
func <#function name#>(<#parameters#>) throws -> <#return type#> {
   <#statements#>
}
```

Una funzione che lancia un tipo di errore specifico ha la forma seguente:

```swift
func <#function name#>(<#parameters#>) throws(<#error type#>) -> <#return type#> {
   <#statements#>
}
```

Le chiamate a una funzione o a un metodo throwing devono essere racchiuse in un'espressione `try` o `try!` (cioè, nell'ambito di un operatore `try` o `try!`).

Il tipo di una funzione include se essa può lanciare un errore e quale tipo di errore lancia. Questa relazione di sottotipo significa, per esempio, che puoi usare una funzione non throwing in un contesto in cui è prevista una funzione throwing. Per maggiori informazioni sul tipo di una funzione throwing, vedi [Tipo funzione](/riferimento-del-linguaggio/tipi.md#tipo-funzione). Per esempi di come lavorare con errori che hanno tipi espliciti, vedi [Specificare il tipo di errore](/guida-al-linguaggio/gestione-degli-errori.md#specificare-il-tipo-di-errore).

Non puoi eseguire l'overload di una funzione basandoti solo sul fatto che la funzione possa lanciare un errore. Detto questo, puoi eseguire l'overload di una funzione basandoti sul fatto che un *parametro* della funzione possa lanciare un errore.

Un metodo throwing non può eseguire l'override di un metodo non throwing, e un metodo throwing non può soddisfare il requisito di un protocollo per un metodo non throwing. Detto questo, un metodo non throwing può eseguire l'override di un metodo throwing, e un metodo non throwing può soddisfare il requisito di un protocollo per un metodo throwing.

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

Una funzione o un metodo può essere dichiarato con la parola chiave `rethrows` per indicare che lancia un errore solo se uno dei suoi parametri funzione lancia un errore. Queste funzioni e questi metodi sono noti come *funzioni rethrowing* e *metodi rethrowing*. Le funzioni e i metodi rethrowing devono avere almeno un parametro funzione throwing.

```swift
func someFunction(callback: () throws -> Void) rethrows {
    try callback()
}
```

Una funzione o un metodo rethrowing può contenere un'istruzione `throw` solo all'interno di una clausola `catch`. Ciò ti permette di chiamare la funzione throwing all'interno di un'istruzione `do`-`catch` e di gestire gli errori nella clausola `catch` lanciando un errore diverso. Inoltre, la clausola `catch` deve gestire solo gli errori lanciati da uno dei parametri throwing della funzione rethrowing. Per esempio, il codice seguente non è valido perché la clausola `catch` gestirebbe l'errore lanciato da `alwaysThrows()`.

```swift
func alwaysThrows() throws {
    throw SomeError.error
}
func someFunction(callback: () throws -> Void) rethrows {
    do {
        try callback()
        try alwaysThrows()  // Non valido, alwaysThrows() non è un parametro throwing
    } catch {
        throw AnotherError.error
    }
}
```

Un metodo throwing non può eseguire l'override di un metodo rethrowing, e un metodo throwing non può soddisfare il requisito di un protocollo per un metodo rethrowing. Detto questo, un metodo rethrowing può eseguire l'override di un metodo throwing, e un metodo rethrowing può soddisfare il requisito di un protocollo per un metodo throwing.

Un'alternativa al rethrowing è lanciare un tipo di errore specifico nel codice generico. Per esempio:

```swift
func someFunction<E: Error>(callback: () throws(E) -> Void) throws(E) {
    try callback()
}
```

Questo approccio alla propagazione di un errore preserva le informazioni sul tipo dell'errore. Tuttavia, a differenza del contrassegnare una funzione con `rethrows`, questo approccio non impedisce alla funzione di lanciare un errore dello stesso tipo.

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

Le funzioni e i metodi eseguiti in modo asincrono devono essere contrassegnati con la parola chiave `async`. Queste funzioni e questi metodi sono noti come *funzioni asincrone* e *metodi asincroni*. Hanno la forma seguente:

```swift
func <#function name#>(<#parameters#>) async -> <#return type#> {
   <#statements#>
}
```

Le chiamate a una funzione o a un metodo asincrono devono essere racchiuse in un'espressione `await` — cioè, devono trovarsi nell'ambito di un operatore `await`.

La parola chiave `async` fa parte del tipo della funzione, e le funzioni sincrone sono sottotipi delle funzioni asincrone. Di conseguenza, puoi usare una funzione sincrona in un contesto in cui è prevista una funzione asincrona. Per esempio, puoi eseguire l'override di un metodo asincrono con un metodo sincrono, e un metodo sincrono può soddisfare il requisito di un protocollo che richiede un metodo asincrono.

Puoi eseguire l'overload di una funzione basandoti sul fatto che la funzione sia asincrona o meno. Nel punto di chiamata, il contesto determina quale overload viene usato: in un contesto asincrono viene usata la funzione asincrona, e in un contesto sincrono viene usata la funzione sincrona.

Un metodo asincrono non può eseguire l'override di un metodo sincrono, e un metodo asincrono non può soddisfare il requisito di un protocollo per un metodo sincrono. Detto questo, un metodo sincrono può eseguire l'override di un metodo asincrono, e un metodo sincrono può soddisfare il requisito di un protocollo per un metodo asincrono.

### Funzioni che non restituiscono mai <a href="#funzioni-che-non-restituiscono-mai" id="funzioni-che-non-restituiscono-mai"></a>

Swift definisce un tipo [`Never`](https://developer.apple.com/documentation/swift/never), che indica che una funzione o un metodo non restituisce il controllo al suo chiamante. Le funzioni e i metodi con tipo di ritorno `Never` sono chiamati *nonreturning*. Le funzioni e i metodi nonreturning causano un errore irrecuperabile oppure avviano una sequenza di lavoro che prosegue indefinitamente. Ciò significa che il codice che altrimenti verrebbe eseguito subito dopo la chiamata non viene mai eseguito. Le funzioni throwing e rethrowing possono trasferire il controllo del programma a un blocco `catch` appropriato, anche quando sono nonreturning.

Una funzione o un metodo nonreturning può essere chiamato per concludere la clausola `else` di un'istruzione guard, come discusso in [Istruzione guard](/riferimento-del-linguaggio/istruzioni.md#istruzione-guard).

Puoi eseguire l'override di un metodo nonreturning, ma il nuovo metodo deve preservarne il tipo di ritorno e il comportamento nonreturning.

{% hint style="info" %}
**Grammatica di una dichiarazione di funzione:**

*function-declaration* → *function-head* *function-name* *generic-parameter-clause?* *function-signature* *generic-where-clause?* *function-body?*

*function-head* → *attributes?* *declaration-modifiers?* **`func`**\
*function-name* → *identifier* | *operator*

*function-signature* → *parameter-clause* **`async`***?* *throws-clause?* *function-result?*\
*function-signature* → *parameter-clause* **`async`***?* **`rethrows`** *function-result?*\
*function-result* → **`->`** *attributes?* *type*\
*function-body* → *code-block*

*parameter-clause* → **`(`** **`)`** | **`(`** *parameter-list* **`,`***?* **`)`**\
*parameter-list* → *parameter* | *parameter* **`,`** *parameter-list*\
*parameter* → *external-parameter-name?* *local-parameter-name* *parameter-type-annotation* *default-argument-clause?*\
*parameter* → *external-parameter-name?* *local-parameter-name* *parameter-type-annotation*\
*parameter* → *external-parameter-name?* *local-parameter-name* *parameter-type-annotation* **`...`**

*external-parameter-name* → *identifier*\
*local-parameter-name* → *identifier*\
*parameter-type-annotation* → **`:`** *attributes?* *parameter-modifier?* *type*\
*parameter-modifier* → **`inout`** | **`borrowing`** | **`consuming`** *default-argument-clause* → **`=`** *expression*
{% endhint %}

## Dichiarazione di enumerazione <a href="#dichiarazione-di-enumerazione" id="dichiarazione-di-enumerazione"></a>

Una *dichiarazione di enumerazione* introduce nel tuo programma un tipo enumerazione con nome.

Le dichiarazioni di enumerazione hanno due forme di base e si dichiarano usando la parola chiave `enum`. Il corpo di un'enumerazione dichiarata usando una delle due forme contiene zero o più valori — chiamati *casi dell'enumerazione* — e un numero qualsiasi di dichiarazioni, tra cui proprietà calcolate, metodi di istanza, metodi di tipo, inizializzatori, alias di tipo, e persino dichiarazioni di altre enumerazioni, strutture, classi e actor. Le dichiarazioni di enumerazione non possono contenere dichiarazioni di deinizializzatori o di protocolli.

I tipi enumerazione possono adottare un numero qualsiasi di protocolli, ma non possono ereditare da classi, strutture o altre enumerazioni.

A differenza delle classi e delle strutture, i tipi enumerazione non hanno un inizializzatore predefinito fornito implicitamente; tutti gli inizializzatori devono essere dichiarati esplicitamente. Gli inizializzatori possono delegare ad altri inizializzatori dell'enumerazione, ma il processo di inizializzazione è completo solo dopo che un inizializzatore ha assegnato uno dei casi dell'enumerazione a `self`.

Come le strutture ma a differenza delle classi, le enumerazioni sono tipi valore; le istanze di un'enumerazione vengono copiate quando vengono assegnate a variabili o costanti, o quando vengono passate come argomenti a una chiamata di funzione. Per informazioni sui tipi valore, vedi [Strutture ed enumerazioni sono tipi valore](/guida-al-linguaggio/strutture-e-classi.md#strutture-ed-enumerazioni-sono-tipi-valore).

Puoi estendere il comportamento di un tipo enumerazione con una dichiarazione di estensione, come discusso in [Dichiarazione di estensione](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-estensione).

### Enumerazioni con casi di qualsiasi tipo <a href="#enumerazioni-con-casi-di-qualsiasi-tipo" id="enumerazioni-con-casi-di-qualsiasi-tipo"></a>

La forma seguente dichiara un tipo enumerazione che contiene casi dell'enumerazione di qualsiasi tipo:

```swift
enum <#enumeration name#>: <#adopted protocols#> {
    case <#enumeration case 1#>
    case <#enumeration case 2#>(<#associated value types#>)
}
```

Le enumerazioni dichiarate in questa forma sono talvolta chiamate *unioni discriminate* in altri linguaggi di programmazione.

In questa forma, ogni blocco case è costituito dalla parola chiave `case` seguita da uno o più casi dell'enumerazione, separati da virgole. Il nome di ciascun caso deve essere univoco. Ogni caso può anche specificare che memorizza valori di un dato tipo. Questi tipi sono specificati nella tupla delle *associated value types* (tipi dei valori associati), subito dopo il nome del caso.

I casi dell'enumerazione che memorizzano valori associati possono essere usati come funzioni che creano istanze dell'enumerazione con i valori associati specificati. E proprio come con le funzioni, puoi ottenere un riferimento a un caso dell'enumerazione e applicarlo in seguito nel tuo codice.

```swift
enum Number {
    case integer(Int)
    case real(Double)
}
let f = Number.integer
// f è una funzione di tipo (Int) -> Number

// Applica f per creare un array di istanze di Number con valori interi
let evenInts: [Number] = [0, 2, 4, 6].map(f)
```

Per maggiori informazioni e per vedere esempi di casi con tipi di valori associati, vedi [Valori associati](/guida-al-linguaggio/enumerazioni.md#valori-associati).

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

Le enumerazioni possono avere una struttura ricorsiva, cioè possono avere casi con valori associati che sono istanze del tipo enumerazione stesso. Tuttavia, le istanze dei tipi enumerazione hanno una semantica di valore, il che significa che hanno una disposizione fissa in memoria. Per supportare la ricorsione, il compilatore deve inserire un livello di indirezione.

Per abilitare l'indirezione per un particolare caso dell'enumerazione, contrassegnalo con il modificatore di dichiarazione `indirect`. Un caso indirect deve avere un valore associato.

```swift
enum Tree<T> {
    case empty
    indirect case node(value: T, left: Tree, right: Tree)
}
```

Per abilitare l'indirezione per tutti i casi di un'enumerazione che hanno un valore associato, contrassegna l'intera enumerazione con il modificatore `indirect` — ciò è comodo quando l'enumerazione contiene molti casi che dovrebbero ciascuno essere contrassegnati con il modificatore `indirect`.

Un'enumerazione contrassegnata con il modificatore `indirect` può contenere una combinazione di casi che hanno valori associati e casi che non ne hanno. Detto questo, non può contenere casi che siano a loro volta contrassegnati con il modificatore `indirect`.

### Enumerazioni con casi di un tipo a valore grezzo <a href="#enumerazioni-con-casi-di-un-tipo-a-valore-grezzo" id="enumerazioni-con-casi-di-un-tipo-a-valore-grezzo"></a>

La forma seguente dichiara un tipo enumerazione che contiene casi dell'enumerazione dello stesso tipo di base:

```swift
enum <#enumeration name#>: <#raw-value type#>, <#adopted protocols#> {
    case <#enumeration case 1#> = <#raw value 1#>
    case <#enumeration case 2#> = <#raw value 2#>
}
```

In questa forma, ogni blocco case è costituito dalla parola chiave `case`, seguita da uno o più casi dell'enumerazione, separati da virgole. A differenza dei casi della prima forma, ogni caso ha un valore sottostante, chiamato *valore grezzo*, dello stesso tipo di base. Il tipo di questi valori è specificato nel *raw-value type* (tipo del valore grezzo) e deve rappresentare un intero, un numero in virgola mobile, una stringa o un singolo carattere. In particolare, il *raw-value type* deve essere conforme al protocollo `Equatable` e a uno dei protocolli seguenti: `ExpressibleByIntegerLiteral` per i letterali interi, `ExpressibleByFloatLiteral` per i letterali in virgola mobile, `ExpressibleByStringLiteral` per i letterali stringa che contengono un numero qualsiasi di caratteri, e `ExpressibleByUnicodeScalarLiteral` o `ExpressibleByExtendedGraphemeClusterLiteral` per i letterali stringa che contengono un solo carattere. Ogni caso deve avere un nome univoco e ricevere un valore grezzo univoco.

Se il tipo del valore grezzo è specificato come `Int` e non assegni esplicitamente un valore ai casi, a questi vengono assegnati implicitamente i valori `0`, `1`, `2` e così via. A ogni caso di tipo `Int` non assegnato viene assegnato implicitamente un valore grezzo che viene incrementato automaticamente a partire dal valore grezzo del caso precedente.

```swift
enum ExampleEnum: Int {
    case a, b, c = 5, d
}
```

Nell'esempio qui sopra, il valore grezzo di `ExampleEnum.a` è `0` e il valore di `ExampleEnum.b` è `1`. E poiché il valore di `ExampleEnum.c` è impostato esplicitamente a `5`, il valore di `ExampleEnum.d` viene incrementato automaticamente a partire da `5` ed è quindi `6`.

Se il tipo del valore grezzo è specificato come `String` e non assegni esplicitamente valori ai casi, a ogni caso non assegnato viene assegnata implicitamente una stringa con lo stesso testo del nome di quel caso.

```swift
enum GamePlayMode: String {
    case cooperative, individual, competitive
}
```

Nell'esempio qui sopra, il valore grezzo di `GamePlayMode.cooperative` è `"cooperative"`, il valore grezzo di `GamePlayMode.individual` è `"individual"`, e il valore grezzo di `GamePlayMode.competitive` è `"competitive"`.

Le enumerazioni che hanno casi di un tipo a valore grezzo sono implicitamente conformi al protocollo `RawRepresentable`, definito nella libreria standard di Swift. Di conseguenza, hanno una proprietà `rawValue` e un inizializzatore failable con la firma `init?(rawValue: RawValue)`. Puoi usare la proprietà `rawValue` per accedere al valore grezzo di un caso dell'enumerazione, come in `ExampleEnum.b.rawValue`. Puoi anche usare un valore grezzo per trovare un caso corrispondente, se esiste, chiamando l'inizializzatore failable dell'enumerazione, come in `ExampleEnum(rawValue: 5)`, che restituisce un caso opzionale. Per maggiori informazioni e per vedere esempi di casi con tipi a valore grezzo, vedi [Valori grezzi](/guida-al-linguaggio/enumerazioni.md#valori-grezzi).

### Accesso ai casi di un'enumerazione <a href="#accesso-ai-casi-di-unenumerazione" id="accesso-ai-casi-di-unenumerazione"></a>

Per fare riferimento al caso di un tipo enumerazione, usa la sintassi con il punto (`.`), come in `EnumerationType.enumerationCase`. Quando il tipo enumerazione può essere inferito dal contesto, puoi ometterlo (il punto è comunque necessario), come descritto in [Sintassi delle enumerazioni](/guida-al-linguaggio/enumerazioni.md#sintassi-delle-enumerazioni) e in [Espressione membro implicita](/riferimento-del-linguaggio/espressioni.md#espressione-membro-implicita).

Per verificare i valori dei casi di un'enumerazione, usa un'istruzione `switch`, come mostrato in [Confrontare i valori di un'enumerazione con un'istruzione switch](/guida-al-linguaggio/enumerazioni.md#confrontare-i-valori-di-unenumerazione-con-unistruzione-switch). Il tipo enumerazione viene confrontato tramite pattern matching con i pattern dei casi dell'enumerazione nei blocchi case dell'istruzione `switch`, come descritto in [Pattern dei casi di enumerazione](/riferimento-del-linguaggio/pattern.md#pattern-dei-casi-di-enumerazione).

{% hint style="info" %}
**Grammatica di una dichiarazione di enumerazione:**

*enum-declaration* → *attributes?* *access-level-modifier?* *union-style-enum*\
*enum-declaration* → *attributes?* *access-level-modifier?* *raw-value-style-enum*

*union-style-enum* → **`indirect`***?* **`enum`** *enum-name* *generic-parameter-clause?* *type-inheritance-clause?* *generic-where-clause?* **`{`** *union-style-enum-members?* **`}`**\
*union-style-enum-members* → *union-style-enum-member* *union-style-enum-members?*\
*union-style-enum-member* → *declaration* | *union-style-enum-case-clause* | *compiler-control-statement*\
*union-style-enum-case-clause* → *attributes?* **`indirect`***?* **`case`** *union-style-enum-case-list*\
*union-style-enum-case-list* → *union-style-enum-case* | *union-style-enum-case* **`,`** *union-style-enum-case-list*\
*union-style-enum-case* → *enum-case-name* *tuple-type?*\
*enum-name* → *identifier*\
*enum-case-name* → *identifier*

*raw-value-style-enum* → **`enum`** *enum-name* *generic-parameter-clause?* *type-inheritance-clause* *generic-where-clause?* **`{`** *raw-value-style-enum-members* **`}`**\
*raw-value-style-enum-members* → *raw-value-style-enum-member* *raw-value-style-enum-members?*\
*raw-value-style-enum-member* → *declaration* | *raw-value-style-enum-case-clause* | *compiler-control-statement*\
*raw-value-style-enum-case-clause* → *attributes?* **`case`** *raw-value-style-enum-case-list*\
*raw-value-style-enum-case-list* → *raw-value-style-enum-case* | *raw-value-style-enum-case* **`,`** *raw-value-style-enum-case-list*\
*raw-value-style-enum-case* → *enum-case-name* *raw-value-assignment?*\
*raw-value-assignment* → **`=`** *raw-value-literal*\
*raw-value-literal* → *numeric-literal* | *static-string-literal* | *boolean-literal*
{% endhint %}

## Dichiarazione di struttura <a href="#dichiarazione-di-struttura" id="dichiarazione-di-struttura"></a>

Una *dichiarazione di struttura* introduce nel tuo programma un tipo struttura con nome. Le dichiarazioni di struttura si dichiarano usando la parola chiave `struct` e hanno la forma seguente:

```swift
struct <#structure name#>: <#adopted protocols#> {
   <#declarations#>
}
```

Il corpo di una struttura contiene zero o più *declarations* (dichiarazioni). Queste *declarations* possono includere proprietà sia memorizzate sia calcolate, proprietà di tipo, metodi di istanza, metodi di tipo, inizializzatori, subscript, alias di tipo, e persino dichiarazioni di altre strutture, classi, actor ed enumerazioni. Le dichiarazioni di struttura non possono contenere dichiarazioni di deinizializzatori o di protocolli. Per una trattazione e diversi esempi di strutture che includono vari tipi di dichiarazioni, vedi [Strutture e classi](/guida-al-linguaggio/strutture-e-classi.md).

I tipi struttura possono adottare un numero qualsiasi di protocolli, ma non possono ereditare da classi, enumerazioni o altre strutture.

Esistono tre modi per creare un'istanza di una struttura dichiarata in precedenza:

* Chiamare uno degli inizializzatori dichiarati all'interno della struttura, come descritto in [Inizializzatori](/guida-al-linguaggio/inizializzazione.md#inizializzatori).
* Se non è dichiarato alcun inizializzatore, chiamare l'inizializzatore memberwise della struttura, come descritto in [Inizializzatori memberwise per i tipi struttura](/guida-al-linguaggio/inizializzazione.md#inizializzatori-memberwise-per-i-tipi-struttura).
* Se non è dichiarato alcun inizializzatore e a tutte le proprietà della dichiarazione della struttura sono stati dati valori iniziali, chiamare l'inizializzatore predefinito della struttura, come descritto in [Inizializzatori predefiniti](/guida-al-linguaggio/inizializzazione.md#inizializzatori-predefiniti).

Il processo di inizializzazione delle proprietà dichiarate di una struttura è descritto in [Inizializzazione](/guida-al-linguaggio/inizializzazione.md).

Si può accedere alle proprietà di un'istanza di una struttura usando la sintassi con il punto (`.`), come descritto in [Accedere alle proprietà](/guida-al-linguaggio/strutture-e-classi.md#accedere-alle-proprieta).

Le strutture sono tipi valore; le istanze di una struttura vengono copiate quando vengono assegnate a variabili o costanti, o quando vengono passate come argomenti a una chiamata di funzione. Per informazioni sui tipi valore, vedi [Strutture ed enumerazioni sono tipi valore](/guida-al-linguaggio/strutture-e-classi.md#strutture-ed-enumerazioni-sono-tipi-valore).

Puoi estendere il comportamento di un tipo struttura con una dichiarazione di estensione, come discusso in [Dichiarazione di estensione](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-estensione).

{% hint style="info" %}
**Grammatica di una dichiarazione di struttura:**

*struct-declaration* → *attributes?* *access-level-modifier?* **`struct`** *struct-name* *generic-parameter-clause?* *type-inheritance-clause?* *generic-where-clause?* *struct-body*\
*struct-name* → *identifier*\
*struct-body* → **`{`** *struct-members?* **`}`**

*struct-members* → *struct-member* *struct-members?*\
*struct-member* → *declaration* | *compiler-control-statement*
{% endhint %}

## Dichiarazione di classe <a href="#dichiarazione-di-classe" id="dichiarazione-di-classe"></a>

Una *dichiarazione di classe* introduce nel tuo programma un tipo classe con nome. Le dichiarazioni di classe si dichiarano usando la parola chiave `class` e hanno la forma seguente:

```swift
class <#class name#>: <#superclass#>, <#adopted protocols#> {
   <#declarations#>
}
```

Il corpo di una classe contiene zero o più *declarations*. Queste *declarations* possono includere proprietà sia memorizzate sia calcolate, metodi di istanza, metodi di tipo, inizializzatori, un solo deinizializzatore, subscript, alias di tipo, e persino dichiarazioni di altre classi, strutture, actor ed enumerazioni. Le dichiarazioni di classe non possono contenere dichiarazioni di protocolli. Per una trattazione e diversi esempi di classi che includono vari tipi di dichiarazioni, vedi [Strutture e classi](/guida-al-linguaggio/strutture-e-classi.md).

Un tipo classe può ereditare da una sola classe genitore, la sua *superclass* (superclasse), ma può adottare un numero qualsiasi di protocolli. La *superclass* compare per prima dopo il *class name* (nome della classe) e i due punti, seguita dagli eventuali *adopted protocols* (protocolli adottati). Le classi generiche possono ereditare da altre classi generiche e non generiche, ma una classe non generica può ereditare solo da altre classi non generiche. Quando scrivi il nome di una superclasse generica dopo i due punti, devi includere il nome completo di quella classe generica, inclusa la sua clausola dei parametri generici.

Come discusso in [Dichiarazione di inizializzatore](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-inizializzatore), le classi possono avere inizializzatori designati e di convenienza. L'inizializzatore designato di una classe deve inizializzare tutte le proprietà dichiarate della classe, e deve farlo prima di chiamare uno qualsiasi degli inizializzatori designati della sua superclasse.

Una classe può eseguire l'override di proprietà, metodi, subscript e inizializzatori della sua superclasse. Le proprietà, i metodi, i subscript e gli inizializzatori designati sottoposti a override devono essere contrassegnati con il modificatore di dichiarazione `override`.

Per richiedere che le sottoclassi implementino un inizializzatore della superclasse, contrassegna l'inizializzatore della superclasse con il modificatore di dichiarazione `required`. Anche l'implementazione di quell'inizializzatore nella sottoclasse deve essere contrassegnata con il modificatore di dichiarazione `required`.

Sebbene le proprietà e i metodi dichiarati nella *superclass* siano ereditati dalla classe corrente, gli inizializzatori designati dichiarati nella *superclass* vengono ereditati solo quando la sottoclasse soddisfa le condizioni descritte in [Ereditarietà automatica degli inizializzatori](/guida-al-linguaggio/inizializzazione.md#ereditarieta-automatica-degli-inizializzatori). Le classi Swift non ereditano da una classe base universale.

Esistono due modi per creare un'istanza di una classe dichiarata in precedenza:

* Chiamare uno degli inizializzatori dichiarati all'interno della classe, come descritto in [Inizializzatori](/guida-al-linguaggio/inizializzazione.md#inizializzatori).
* Se non è dichiarato alcun inizializzatore e a tutte le proprietà della dichiarazione della classe sono stati dati valori iniziali, chiamare l'inizializzatore predefinito della classe, come descritto in [Inizializzatori predefiniti](/guida-al-linguaggio/inizializzazione.md#inizializzatori-predefiniti).

Accedi alle proprietà di un'istanza di una classe con la sintassi con il punto (`.`), come descritto in [Accedere alle proprietà](/guida-al-linguaggio/strutture-e-classi.md#accedere-alle-proprieta).

Le classi sono tipi riferimento; alle istanze di una classe si fa riferimento, anziché copiarle, quando vengono assegnate a variabili o costanti, o quando vengono passate come argomenti a una chiamata di funzione. Per informazioni sui tipi riferimento, vedi [Le classi sono tipi riferimento](/guida-al-linguaggio/strutture-e-classi.md#le-classi-sono-tipi-riferimento).

Puoi estendere il comportamento di un tipo classe con una dichiarazione di estensione, come discusso in [Dichiarazione di estensione](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-estensione).

{% hint style="info" %}
**Grammatica di una dichiarazione di classe:**

*class-declaration* → *attributes?* *access-level-modifier?* **`final`***?* **`class`** *class-name* *generic-parameter-clause?* *type-inheritance-clause?* *generic-where-clause?* *class-body*\
*class-declaration* → *attributes?* **`final`** *access-level-modifier?* **`class`** *class-name* *generic-parameter-clause?* *type-inheritance-clause?* *generic-where-clause?* *class-body*\
*class-name* → *identifier*\
*class-body* → **`{`** *class-members?* **`}`**

*class-members* → *class-member* *class-members?*\
*class-member* → *declaration* | *compiler-control-statement*
{% endhint %}

## Dichiarazione di actor <a href="#dichiarazione-di-actor" id="dichiarazione-di-actor"></a>

Una *dichiarazione di actor* introduce nel tuo programma un tipo actor con nome. Le dichiarazioni di actor si dichiarano usando la parola chiave `actor` e hanno la forma seguente:

```swift
actor <#actor name#>: <#adopted protocols#> {
    <#declarations#>
}
```

Il corpo di un actor contiene zero o più *declarations*. Queste *declarations* possono includere proprietà sia memorizzate sia calcolate, metodi di istanza, metodi di tipo, inizializzatori, un solo deinizializzatore, subscript, alias di tipo, e persino dichiarazioni di altre classi, strutture ed enumerazioni. Per una trattazione e diversi esempi di actor che includono vari tipi di dichiarazioni, vedi [Actor](/guida-al-linguaggio/concorrenza.md#actor).

I tipi actor possono adottare un numero qualsiasi di protocolli, ma non possono ereditare da classi, enumerazioni, strutture o altri actor. Tuttavia, un actor contrassegnato con l'attributo `@objc` è implicitamente conforme al protocollo `NSObjectProtocol` ed è esposto al runtime di Objective-C come sottotipo di `NSObject`.

Esistono due modi per creare un'istanza di un actor dichiarato in precedenza:

* Chiamare uno degli inizializzatori dichiarati all'interno dell'actor, come descritto in [Inizializzatori](/guida-al-linguaggio/inizializzazione.md#inizializzatori).
* Se non è dichiarato alcun inizializzatore e a tutte le proprietà della dichiarazione dell'actor sono stati dati valori iniziali, chiamare l'inizializzatore predefinito dell'actor, come descritto in [Inizializzatori predefiniti](/guida-al-linguaggio/inizializzazione.md#inizializzatori-predefiniti).

Per impostazione predefinita, i membri di un actor sono isolati rispetto a quell'actor. Il codice, come il corpo di un metodo o il getter di una proprietà, viene eseguito su quell'actor. Il codice all'interno dell'actor può interagire con essi in modo sincrono perché quel codice è già in esecuzione sullo stesso actor, ma il codice al di fuori dell'actor deve contrassegnarli con `await` per indicare che quel codice esegue in modo asincrono codice su un altro actor. I key path non possono fare riferimento a membri isolati di un actor. Le proprietà memorizzate isolate rispetto all'actor possono essere passate come parametri in-out a funzioni sincrone, ma non a funzioni asincrone.

Gli actor possono avere anche membri non isolati, le cui dichiarazioni sono contrassegnate con la parola chiave `nonisolated`. Un membro non isolato viene eseguito come il codice al di fuori dell'actor: non può interagire con alcuno stato isolato dell'actor, e i chiamanti non lo contrassegnano con `await` quando lo usano.

I membri di un actor possono essere contrassegnati con l'attributo `@objc` solo se sono non isolati o asincroni.

Il processo di inizializzazione delle proprietà dichiarate di un actor è descritto in [Inizializzazione](/guida-al-linguaggio/inizializzazione.md).

Si può accedere alle proprietà di un'istanza di un actor usando la sintassi con il punto (`.`), come descritto in [Accedere alle proprietà](/guida-al-linguaggio/strutture-e-classi.md#accedere-alle-proprieta).

Gli actor sono tipi riferimento; alle istanze di un actor si fa riferimento, anziché copiarle, quando vengono assegnate a variabili o costanti, o quando vengono passate come argomenti a una chiamata di funzione. Per informazioni sui tipi riferimento, vedi [Le classi sono tipi riferimento](/guida-al-linguaggio/strutture-e-classi.md#le-classi-sono-tipi-riferimento).

Puoi estendere il comportamento di un tipo actor con una dichiarazione di estensione, come discusso in [Dichiarazione di estensione](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-estensione).

{% hint style="info" %}
**Grammatica di una dichiarazione di actor:**

*actor-declaration* → *attributes?* *access-level-modifier?* **`actor`** *actor-name* *generic-parameter-clause?* *type-inheritance-clause?* *generic-where-clause?* *actor-body*\
*actor-name* → *identifier*\
*actor-body* → **`{`** *actor-members?* **`}`**

*actor-members* → *actor-member* *actor-members?*\
*actor-member* → *declaration* | *compiler-control-statement*
{% endhint %}

## Dichiarazione di protocollo <a href="#dichiarazione-di-protocollo" id="dichiarazione-di-protocollo"></a>

Una *dichiarazione di protocollo* introduce nel tuo programma un tipo protocollo con nome. Le dichiarazioni di protocollo si dichiarano usando la parola chiave `protocol` e hanno la forma seguente:

```swift
protocol <#protocol name#>: <#inherited protocols#> {
   <#protocol member declarations#>
}
```

Le dichiarazioni di protocollo possono comparire nell'ambito globale, oppure annidate all'interno di un tipo non generico o di una funzione non generica.

Il corpo di un protocollo contiene zero o più *protocol member declarations* (dichiarazioni di membri del protocollo), che descrivono i requisiti di conformità che qualsiasi tipo che adotta il protocollo deve soddisfare. In particolare, un protocollo può dichiarare che i tipi conformi devono implementare determinate proprietà, metodi, inizializzatori e subscript. I protocolli possono anche dichiarare tipi speciali di alias di tipo, chiamati *tipi associati*, che possono specificare relazioni tra le varie dichiarazioni del protocollo. Le dichiarazioni di protocollo non possono contenere dichiarazioni di classi, strutture, enumerazioni o altri protocolli. Le *protocol member declarations* sono trattate in dettaglio più avanti.

I tipi protocollo possono ereditare da un numero qualsiasi di altri protocolli. Quando un tipo protocollo eredita da altri protocolli, l'insieme dei requisiti di quegli altri protocolli viene aggregato, e qualsiasi tipo che eredita dal protocollo corrente deve essere conforme a tutti quei requisiti. Per un esempio di come usare l'ereditarietà dei protocolli, vedi [Ereditarietà dei protocolli](/guida-al-linguaggio/protocolli.md#ereditarieta-dei-protocolli).

{% hint style="info" %}
**Nota:** Puoi anche aggregare i requisiti di conformità di più protocolli usando i tipi composizione di protocolli, come descritto in [Tipo composizione di protocolli](/riferimento-del-linguaggio/tipi.md#tipo-composizione-di-protocolli) e in [Composizione di protocolli](/guida-al-linguaggio/protocolli.md#composizione-di-protocolli).
{% endhint %}

Puoi aggiungere la conformità a un protocollo a un tipo dichiarato in precedenza adottando il protocollo in una dichiarazione di estensione di quel tipo. Nell'estensione, devi implementare tutti i requisiti del protocollo adottato. Se il tipo implementa già tutti i requisiti, puoi lasciare vuoto il corpo della dichiarazione di estensione.

Per impostazione predefinita, i tipi conformi a un protocollo devono implementare tutte le proprietà, i metodi e i subscript dichiarati nel protocollo. Detto questo, puoi contrassegnare queste dichiarazioni di membri del protocollo con il modificatore di dichiarazione `optional` per specificare che la loro implementazione da parte di un tipo conforme è facoltativa. Il modificatore `optional` può essere applicato solo ai membri contrassegnati con l'attributo `objc`, e solo ai membri di protocolli contrassegnati con l'attributo `objc`. Di conseguenza, solo i tipi classe possono adottare ed essere conformi a un protocollo che contiene requisiti di membri facoltativi. Per maggiori informazioni su come usare il modificatore di dichiarazione `optional` e per indicazioni su come accedere ai membri facoltativi di un protocollo — per esempio, quando non sei sicuro che un tipo conforme li implementi — vedi [Requisiti opzionali dei protocolli](/guida-al-linguaggio/protocolli.md#requisiti-opzionali-dei-protocolli).

I casi di un'enumerazione possono soddisfare i requisiti di un protocollo per i membri di tipo. Nello specifico, un caso dell'enumerazione senza valori associati soddisfa il requisito di un protocollo per una variabile di tipo di sola lettura di tipo `Self`, e un caso dell'enumerazione con valori associati soddisfa il requisito di un protocollo per una funzione che restituisce `Self` i cui parametri e le relative etichette dell'argomento corrispondono ai valori associati del caso. Per esempio:

```swift
protocol SomeProtocol {
    static var someValue: Self { get }
    static func someFunction(x: Int) -> Self
}
enum MyEnum: SomeProtocol {
    case someValue
    case someFunction(x: Int)
}
```

Per limitare l'adozione di un protocollo ai soli tipi classe, includi il protocollo `AnyObject` nell'elenco degli *inherited protocols* (protocolli ereditati) dopo i due punti. Per esempio, il protocollo seguente può essere adottato solo da tipi classe:

```swift
protocol SomeProtocol: AnyObject {
    /* Qui vanno i membri del protocollo. */
}
```

Qualsiasi protocollo che eredita da un protocollo contrassegnato con il requisito `AnyObject` può analogamente essere adottato solo da tipi classe.

{% hint style="info" %}
**Nota:** Se un protocollo è contrassegnato con l'attributo `objc`, il requisito `AnyObject` viene applicato implicitamente a quel protocollo; non è necessario contrassegnare esplicitamente il protocollo con il requisito `AnyObject`.
{% endhint %}

Puoi anche indicare una classe specifica nell'elenco degli *inherited protocols* per limitare l'adozione del protocollo alle sottoclassi di quella classe. Per esempio, il protocollo seguente può essere adottato solo da sottoclassi di `SomeBaseClass`:

```swift
class SomeBaseClass { /* ... */ }
protocol SomeRefinedProtocol: SomeBaseClass {
    /* Qui vanno i membri del protocollo. */
}
```

I protocolli sono tipi con nome, e quindi possono comparire in tutti gli stessi punti del tuo codice degli altri tipi con nome, come discusso in [I protocolli come tipi](/guida-al-linguaggio/protocolli.md#i-protocolli-come-tipi). Tuttavia, non puoi costruire un'istanza di un protocollo, perché i protocolli non forniscono effettivamente le implementazioni dei requisiti che specificano.

Puoi usare i protocolli per dichiarare quali metodi un delegato di una classe o di una struttura dovrebbe implementare, come descritto in [Delega](/guida-al-linguaggio/protocolli.md#delega).

{% hint style="info" %}
**Grammatica di una dichiarazione di protocollo:**

*protocol-declaration* → *attributes?* *access-level-modifier?* **`protocol`** *protocol-name* *type-inheritance-clause?* *generic-where-clause?* *protocol-body*\
*protocol-name* → *identifier*\
*protocol-body* → **`{`** *protocol-members?* **`}`**

*protocol-members* → *protocol-member* *protocol-members?*\
*protocol-member* → *protocol-member-declaration* | *compiler-control-statement*

*protocol-member-declaration* → *protocol-property-declaration*\
*protocol-member-declaration* → *protocol-method-declaration*\
*protocol-member-declaration* → *protocol-initializer-declaration*\
*protocol-member-declaration* → *protocol-subscript-declaration*\
*protocol-member-declaration* → *protocol-associated-type-declaration*\
*protocol-member-declaration* → *typealias-declaration*
{% endhint %}

### Dichiarazione di proprietà di un protocollo <a href="#dichiarazione-di-proprieta-di-un-protocollo" id="dichiarazione-di-proprieta-di-un-protocollo"></a>

I protocolli dichiarano che i tipi conformi devono implementare una proprietà includendo una *dichiarazione di proprietà del protocollo* nel corpo della dichiarazione del protocollo. Le dichiarazioni di proprietà dei protocolli hanno una forma speciale di dichiarazione di variabile:

```swift
var <#property name#>: <#type#> { get set }
```

Come per le altre dichiarazioni di membri dei protocolli, queste dichiarazioni di proprietà dichiarano solo i requisiti di getter e setter per i tipi conformi al protocollo. Di conseguenza, non implementi il getter o il setter direttamente nel protocollo in cui è dichiarato.

I requisiti di getter e setter possono essere soddisfatti da un tipo conforme in diversi modi. Se la dichiarazione di una proprietà include sia la parola chiave `get` sia la parola chiave `set`, un tipo conforme può implementarla con una proprietà variabile memorizzata o con una proprietà calcolata sia leggibile sia scrivibile (cioè una che implementa sia un getter sia un setter). Tuttavia, quella dichiarazione di proprietà non può essere implementata come proprietà costante o come proprietà calcolata di sola lettura. Se la dichiarazione di una proprietà include solo la parola chiave `get`, può essere implementata come qualsiasi tipo di proprietà. Per esempi di tipi conformi che implementano i requisiti di proprietà di un protocollo, vedi [Requisiti di proprietà](/guida-al-linguaggio/protocolli.md#requisiti-di-proprieta).

Per dichiarare un requisito di proprietà di tipo nella dichiarazione di un protocollo, contrassegna la dichiarazione della proprietà con la parola chiave `static`. Le strutture e le enumerazioni conformi al protocollo dichiarano la proprietà con la parola chiave `static`, e le classi conformi al protocollo dichiarano la proprietà con la parola chiave `static` o `class`. Le estensioni che aggiungono la conformità al protocollo a una struttura, a un'enumerazione o a una classe usano la stessa parola chiave usata dal tipo che estendono. Le estensioni che forniscono un'implementazione predefinita per un requisito di proprietà di tipo usano la parola chiave `static`.

Vedi anche [Dichiarazione di variabile](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-variabile).

{% hint style="info" %}
**Grammatica di una dichiarazione di proprietà di un protocollo:**

*protocol-property-declaration* → *variable-declaration-head* *variable-name* *type-annotation* *getter-setter-keyword-block*
{% endhint %}

### Dichiarazione di metodo di un protocollo <a href="#dichiarazione-di-metodo-di-un-protocollo" id="dichiarazione-di-metodo-di-un-protocollo"></a>

I protocolli dichiarano che i tipi conformi devono implementare un metodo includendo una dichiarazione di metodo del protocollo nel corpo della dichiarazione del protocollo. Le dichiarazioni di metodo dei protocolli hanno la stessa forma delle dichiarazioni di funzione, con due eccezioni: non includono il corpo della funzione, e non puoi fornire valori predefiniti dei parametri come parte della dichiarazione della funzione. Per esempi di tipi conformi che implementano i requisiti di metodo di un protocollo, vedi [Requisiti di metodo](/guida-al-linguaggio/protocolli.md#requisiti-di-metodo).

Per dichiarare un requisito di metodo di classe o statico nella dichiarazione di un protocollo, contrassegna la dichiarazione del metodo con il modificatore di dichiarazione `static`. Le strutture e le enumerazioni conformi al protocollo dichiarano il metodo con la parola chiave `static`, e le classi conformi al protocollo dichiarano il metodo con la parola chiave `static` o `class`. Le estensioni che aggiungono la conformità al protocollo a una struttura, a un'enumerazione o a una classe usano la stessa parola chiave usata dal tipo che estendono. Le estensioni che forniscono un'implementazione predefinita per un requisito di metodo di tipo usano la parola chiave `static`.

Vedi anche [Dichiarazione di funzione](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-funzione).

{% hint style="info" %}
**Grammatica di una dichiarazione di metodo di un protocollo:**

*protocol-method-declaration* → *function-head* *function-name* *generic-parameter-clause?* *function-signature* *generic-where-clause?*
{% endhint %}

### Dichiarazione di inizializzatore di un protocollo <a href="#dichiarazione-di-inizializzatore-di-un-protocollo" id="dichiarazione-di-inizializzatore-di-un-protocollo"></a>

I protocolli dichiarano che i tipi conformi devono implementare un inizializzatore includendo una dichiarazione di inizializzatore del protocollo nel corpo della dichiarazione del protocollo. Le dichiarazioni di inizializzatore dei protocolli hanno la stessa forma delle dichiarazioni di inizializzatore, tranne per il fatto che non includono il corpo dell'inizializzatore.

Un tipo conforme può soddisfare il requisito di un inizializzatore non failable di un protocollo implementando un inizializzatore non failable o un inizializzatore failable `init!`. Un tipo conforme può soddisfare il requisito di un inizializzatore failable di un protocollo implementando qualsiasi tipo di inizializzatore.

Quando una classe implementa un inizializzatore per soddisfare il requisito di inizializzatore di un protocollo, l'inizializzatore deve essere contrassegnato con il modificatore di dichiarazione `required` se la classe non è già contrassegnata con il modificatore di dichiarazione `final`.

Vedi anche [Dichiarazione di inizializzatore](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-inizializzatore).

{% hint style="info" %}
**Grammatica di una dichiarazione di inizializzatore di un protocollo:**

*protocol-initializer-declaration* → *initializer-head* *generic-parameter-clause?* *parameter-clause* *throws-clause?* *generic-where-clause?*\
*protocol-initializer-declaration* → *initializer-head* *generic-parameter-clause?* *parameter-clause* **`rethrows`** *generic-where-clause?*
{% endhint %}

### Dichiarazione di subscript di un protocollo <a href="#dichiarazione-di-subscript-di-un-protocollo" id="dichiarazione-di-subscript-di-un-protocollo"></a>

I protocolli dichiarano che i tipi conformi devono implementare un subscript includendo una dichiarazione di subscript del protocollo nel corpo della dichiarazione del protocollo. Le dichiarazioni di subscript dei protocolli hanno una forma speciale di dichiarazione di subscript:

```swift
subscript (<#parameters#>) -> <#return type#> { get set }
```

Le dichiarazioni di subscript dichiarano solo i requisiti minimi di implementazione di getter e setter per i tipi conformi al protocollo. Se la dichiarazione del subscript include sia la parola chiave `get` sia la parola chiave `set`, un tipo conforme deve implementare sia una clausola getter sia una clausola setter. Se la dichiarazione del subscript include solo la parola chiave `get`, un tipo conforme deve implementare *almeno* una clausola getter e facoltativamente può implementare una clausola setter.

Per dichiarare un requisito di subscript statico nella dichiarazione di un protocollo, contrassegna la dichiarazione del subscript con il modificatore di dichiarazione `static`. Le strutture e le enumerazioni conformi al protocollo dichiarano il subscript con la parola chiave `static`, e le classi conformi al protocollo dichiarano il subscript con la parola chiave `static` o `class`. Le estensioni che aggiungono la conformità al protocollo a una struttura, a un'enumerazione o a una classe usano la stessa parola chiave usata dal tipo che estendono. Le estensioni che forniscono un'implementazione predefinita per un requisito di subscript statico usano la parola chiave `static`.

Vedi anche [Dichiarazione di subscript](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-subscript).

{% hint style="info" %}
**Grammatica di una dichiarazione di subscript di un protocollo:**

*protocol-subscript-declaration* → *subscript-head* *subscript-result* *generic-where-clause?* *getter-setter-keyword-block*
{% endhint %}

### Dichiarazione di tipo associato di un protocollo <a href="#dichiarazione-di-tipo-associato-di-un-protocollo" id="dichiarazione-di-tipo-associato-di-un-protocollo"></a>

I protocolli dichiarano i tipi associati usando la parola chiave `associatedtype`. Un tipo associato fornisce un alias per un tipo usato come parte della dichiarazione di un protocollo. I tipi associati sono simili ai parametri di tipo nelle clausole dei parametri generici, ma sono associati a `Self` nel protocollo in cui sono dichiarati. In quel contesto, `Self` fa riferimento al tipo che alla fine sarà conforme al protocollo. Per maggiori informazioni ed esempi, vedi [Tipi associati](/guida-al-linguaggio/generici.md#tipi-associati).

Usi una clausola `where` generica nella dichiarazione di un protocollo per aggiungere vincoli ai tipi associati ereditati da un altro protocollo, senza dichiarare di nuovo i tipi associati. Per esempio, le dichiarazioni di `SubProtocol` seguenti sono equivalenti:

```swift
protocol SomeProtocol {
    associatedtype SomeType
}

protocol SubProtocolA: SomeProtocol {
    // Questa sintassi produce un avviso.
    associatedtype SomeType: Equatable
}

// Questa sintassi è preferibile.
protocol SubProtocolB: SomeProtocol where SomeType: Equatable { }
```

Vedi anche [Dichiarazione di alias di tipo](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-alias-di-tipo).

{% hint style="info" %}
**Grammatica di una dichiarazione di tipo associato di un protocollo:**

*protocol-associated-type-declaration* → *attributes?* *access-level-modifier?* **`associatedtype`** *typealias-name* *type-inheritance-clause?* *typealias-assignment?* *generic-where-clause?*
{% endhint %}

## Dichiarazione di inizializzatore <a href="#dichiarazione-di-inizializzatore" id="dichiarazione-di-inizializzatore"></a>

Una *dichiarazione di inizializzatore* introduce nel tuo programma un inizializzatore per una classe, una struttura o un'enumerazione. Le dichiarazioni di inizializzatore si dichiarano usando la parola chiave `init` e hanno due forme di base.

I tipi struttura, enumerazione e classe possono avere un numero qualsiasi di inizializzatori, ma le regole e il comportamento associato per gli inizializzatori delle classi sono diversi. A differenza delle strutture e delle enumerazioni, le classi hanno due tipi di inizializzatori: inizializzatori designati e inizializzatori di convenienza, come descritto in [Inizializzazione](/guida-al-linguaggio/inizializzazione.md).

La forma seguente dichiara gli inizializzatori per strutture, enumerazioni e gli inizializzatori designati delle classi:

```swift
init(<#parameters#>) {
   <#statements#>
}
```

Un inizializzatore designato di una classe inizializza direttamente tutte le proprietà della classe. Non può chiamare altri inizializzatori della stessa classe, e se la classe ha una superclasse, deve chiamare uno degli inizializzatori designati della superclasse. Se la classe eredita delle proprietà dalla sua superclasse, uno degli inizializzatori designati della superclasse deve essere chiamato prima che una qualsiasi di queste proprietà possa essere impostata o modificata nella classe corrente.

Gli inizializzatori designati possono essere dichiarati solo nel contesto della dichiarazione di una classe e quindi non possono essere aggiunti a una classe usando una dichiarazione di estensione.

Gli inizializzatori delle strutture e delle enumerazioni possono chiamare altri inizializzatori dichiarati per delegare parte o tutto il processo di inizializzazione.

Per dichiarare inizializzatori di convenienza per una classe, contrassegna la dichiarazione dell'inizializzatore con il modificatore di dichiarazione `convenience`.

```swift
convenience init(<#parameters#>) {
   <#statements#>
}
```

Gli inizializzatori di convenienza possono delegare il processo di inizializzazione a un altro inizializzatore di convenienza o a uno degli inizializzatori designati della classe. Detto questo, i processi di inizializzazione devono terminare con una chiamata a un inizializzatore designato che alla fine inizializza le proprietà della classe. Gli inizializzatori di convenienza non possono chiamare gli inizializzatori di una superclasse.

Puoi contrassegnare gli inizializzatori designati e di convenienza con il modificatore di dichiarazione `required` per richiedere che ogni sottoclasse implementi l'inizializzatore. Anche l'implementazione di quell'inizializzatore in una sottoclasse deve essere contrassegnata con il modificatore di dichiarazione `required`.

Per impostazione predefinita, gli inizializzatori dichiarati in una superclasse non vengono ereditati dalle sottoclassi. Detto questo, se una sottoclasse inizializza tutte le sue proprietà memorizzate con valori predefiniti e non definisce alcun inizializzatore proprio, eredita tutti gli inizializzatori della superclasse. Se la sottoclasse esegue l'override di tutti gli inizializzatori designati della superclasse, eredita gli inizializzatori di convenienza della superclasse.

Come per metodi, proprietà e subscript, devi contrassegnare gli inizializzatori designati sottoposti a override con il modificatore di dichiarazione `override`.

{% hint style="info" %}
**Nota:** Se contrassegni un inizializzatore con il modificatore di dichiarazione `required`, non contrassegni anche l'inizializzatore con il modificatore `override` quando esegui l'override dell'inizializzatore required in una sottoclasse.
{% endhint %}

Proprio come le funzioni e i metodi, gli inizializzatori possono lanciare o rilanciare errori. E proprio come per le funzioni e i metodi, usi la parola chiave `throws` o `rethrows` dopo i parametri di un inizializzatore per indicare il comportamento appropriato. Analogamente, gli inizializzatori possono essere asincroni, e usi la parola chiave `async` per indicarlo.

Per vedere esempi di inizializzatori in varie dichiarazioni di tipo, vedi [Inizializzazione](/guida-al-linguaggio/inizializzazione.md).

### Inizializzatori failable <a href="#inizializzatori-failable" id="inizializzatori-failable"></a>

Un *inizializzatore failable* è un tipo di inizializzatore che produce un'istanza opzionale o un'istanza opzionale con unwrapping implicito del tipo su cui l'inizializzatore è dichiarato. Di conseguenza, un inizializzatore failable può restituire `nil` per indicare che l'inizializzazione è fallita.

Per dichiarare un inizializzatore failable che produce un'istanza opzionale, aggiungi un punto interrogativo alla parola chiave `init` nella dichiarazione dell'inizializzatore (`init?`). Per dichiarare un inizializzatore failable che produce un'istanza opzionale con unwrapping implicito, aggiungi invece un punto esclamativo (`init!`). L'esempio seguente mostra un inizializzatore failable `init?` che produce un'istanza opzionale di una struttura.

```swift
struct SomeStruct {
    let property: String
    // produce un'istanza opzionale di 'SomeStruct'
    init?(input: String) {
        if input.isEmpty {
            // scarta 'self' e restituisce 'nil'
            return nil
        }
        property = input
    }
}
```

Chiami un inizializzatore failable `init?` nello stesso modo in cui chiami un inizializzatore non failable, tranne per il fatto che devi gestire l'opzionalità del risultato.

```swift
if let actualInstance = SomeStruct(input: "Hello") {
    // fai qualcosa con l'istanza di 'SomeStruct'
} else {
    // l'inizializzazione di 'SomeStruct' è fallita e l'inizializzatore ha restituito 'nil'
}
```

Un inizializzatore failable può restituire `nil` in qualsiasi punto dell'implementazione del corpo dell'inizializzatore.

Un inizializzatore failable può delegare a qualsiasi tipo di inizializzatore. Un inizializzatore non failable può delegare a un altro inizializzatore non failable o a un inizializzatore failable `init!`. Un inizializzatore non failable può delegare a un inizializzatore failable `init?` eseguendo l'unwrapping forzato del risultato dell'inizializzatore della superclasse — per esempio, scrivendo `super.init()!`.

Il fallimento dell'inizializzazione si propaga attraverso la delega degli inizializzatori. Nello specifico, se un inizializzatore failable delega a un inizializzatore che fallisce e restituisce `nil`, anche l'inizializzatore che ha delegato fallisce e restituisce implicitamente `nil`. Se un inizializzatore non failable delega a un inizializzatore failable `init!` che fallisce e restituisce `nil`, viene generato un errore in fase di esecuzione (come se avessi usato l'operatore `!` per eseguire l'unwrapping di un opzionale che ha valore `nil`).

Un inizializzatore designato failable può essere sottoposto a override in una sottoclasse da qualsiasi tipo di inizializzatore designato. Un inizializzatore designato non failable può essere sottoposto a override in una sottoclasse solo da un inizializzatore designato non failable.

Per maggiori informazioni e per vedere esempi di inizializzatori failable, vedi [Inizializzatori failable](/guida-al-linguaggio/inizializzazione.md#inizializzatori-failable).

{% hint style="info" %}
**Grammatica di una dichiarazione di inizializzatore:**

*initializer-declaration* → *initializer-head* *generic-parameter-clause?* *parameter-clause* **`async`***?* *throws-clause?* *generic-where-clause?* *initializer-body*\
*initializer-declaration* → *initializer-head* *generic-parameter-clause?* *parameter-clause* **`async`***?* **`rethrows`** *generic-where-clause?* *initializer-body*\
*initializer-head* → *attributes?* *declaration-modifiers?* **`init`**\
*initializer-head* → *attributes?* *declaration-modifiers?* **`init`** **`?`**\
*initializer-head* → *attributes?* *declaration-modifiers?* **`init`** **`!`**\
*initializer-body* → *code-block*
{% endhint %}

## Dichiarazione di deinizializzatore <a href="#dichiarazione-di-deinizializzatore" id="dichiarazione-di-deinizializzatore"></a>

Una *dichiarazione di deinizializzatore* dichiara un deinizializzatore per un tipo classe. I deinizializzatori non accettano parametri e hanno la forma seguente:

```swift
deinit {
   <#statements#>
}
```

Un deinizializzatore viene chiamato automaticamente quando non esistono più riferimenti a un oggetto di una classe, subito prima che l'oggetto venga deallocato. Un deinizializzatore può essere dichiarato solo nel corpo della dichiarazione di una classe — ma non in un'estensione di una classe — e ogni classe può averne al massimo uno.

Una sottoclasse eredita il deinizializzatore della sua superclasse, che viene chiamato implicitamente subito prima che l'oggetto della sottoclasse venga deallocato. L'oggetto della sottoclasse non viene deallocato finché tutti i deinizializzatori della sua catena di ereditarietà non hanno terminato l'esecuzione.

I deinizializzatori non vengono chiamati direttamente.

Per un esempio di come usare un deinizializzatore nella dichiarazione di una classe, vedi [Deinizializzazione](/guida-al-linguaggio/deinizializzazione.md).

{% hint style="info" %}
**Grammatica di una dichiarazione di deinizializzatore:**

*deinitializer-declaration* → *attributes?* **`deinit`** *code-block*
{% endhint %}

## Dichiarazione di estensione <a href="#dichiarazione-di-estensione" id="dichiarazione-di-estensione"></a>

Una *dichiarazione di estensione* ti permette di estendere il comportamento di tipi esistenti. Le dichiarazioni di estensione si dichiarano usando la parola chiave `extension` e hanno la forma seguente:

```swift
extension <#type name#> where <#requirements#> {
   <#declarations#>
}
```

Il corpo di una dichiarazione di estensione contiene zero o più *declarations*. Queste *declarations* possono includere proprietà calcolate, proprietà di tipo calcolate, metodi di istanza, metodi di tipo, inizializzatori, dichiarazioni di subscript, e persino dichiarazioni di classi, strutture ed enumerazioni. Le dichiarazioni di estensione non possono contenere dichiarazioni di deinizializzatori o di protocolli, proprietà memorizzate, osservatori di proprietà o altre dichiarazioni di estensione. Le dichiarazioni in un'estensione di protocollo non possono essere contrassegnate come `final`. Per una trattazione e diversi esempi di estensioni che includono vari tipi di dichiarazioni, vedi [Estensioni](/guida-al-linguaggio/estensioni.md).

Se il *type name* è un tipo classe, struttura o enumerazione, l'estensione estende quel tipo. Se il *type name* è un tipo protocollo, l'estensione estende tutti i tipi conformi a quel protocollo.

Le dichiarazioni di estensione che estendono un tipo generico o un protocollo con tipi associati possono includere dei *requirements* (requisiti). Se un'istanza del tipo esteso o di un tipo conforme al protocollo esteso soddisfa i *requirements*, l'istanza acquisisce il comportamento specificato nella dichiarazione.

Le dichiarazioni di estensione possono contenere dichiarazioni di inizializzatori. Detto questo, se il tipo che stai estendendo è definito in un altro modulo, una dichiarazione di inizializzatore deve delegare a un inizializzatore già definito in quel modulo per garantire che i membri di quel tipo siano inizializzati correttamente.

Le proprietà, i metodi e gli inizializzatori di un tipo esistente non possono essere sottoposti a override in un'estensione di quel tipo.

Le dichiarazioni di estensione possono aggiungere la conformità a protocolli a un tipo classe, struttura o enumerazione esistente specificando degli *adopted protocols*:

```swift
extension <#type name#>: <#adopted protocols#> where <#requirements#> {
   <#declarations#>
}
```

Le dichiarazioni di estensione non possono aggiungere l'ereditarietà di classe a una classe esistente, e quindi dopo il *type name* e i due punti puoi specificare solo un elenco di protocolli.

### Conformità condizionale <a href="#conformita-condizionale" id="conformita-condizionale"></a>

Puoi estendere un tipo generico per renderlo condizionalmente conforme a un protocollo, così che le istanze del tipo siano conformi al protocollo solo quando sono soddisfatti determinati requisiti. Aggiungi la conformità condizionale a un protocollo includendo dei *requirements* in una dichiarazione di estensione.

#### I requisiti sottoposti a override non vengono usati in alcuni contesti generici <a href="#i-requisiti-sottoposti-a-override-non-vengono-usati-in-alcuni-contesti-generici" id="i-requisiti-sottoposti-a-override-non-vengono-usati-in-alcuni-contesti-generici"></a>

In alcuni contesti generici, i tipi che ottengono un comportamento dalla conformità condizionale a un protocollo non usano sempre le implementazioni specializzate dei requisiti di quel protocollo. Per illustrare questo comportamento, l'esempio seguente definisce due protocolli e un tipo generico condizionalmente conforme a entrambi i protocolli.

```swift
protocol Loggable {
    func log()
}
extension Loggable {
    func log() {
        print(self)
    }
}

protocol TitledLoggable: Loggable {
    static var logTitle: String { get }
}
extension TitledLoggable {
    func log() {
        print("\(Self.logTitle): \(self)")
    }
}

struct Pair<T>: CustomStringConvertible {
    let first: T
    let second: T
    var description: String {
        return "(\(first), \(second))"
    }
}

extension Pair: Loggable where T: Loggable { }
extension Pair: TitledLoggable where T: TitledLoggable {
    static var logTitle: String {
        return "Pair of '\(T.logTitle)'"
    }
}

extension String: TitledLoggable {
    static var logTitle: String {
        return "String"
    }
}
```

La struttura `Pair` è conforme a `Loggable` e a `TitledLoggable` ogni volta che il suo tipo generico è conforme rispettivamente a `Loggable` o a `TitledLoggable`. Nell'esempio seguente, `oneAndTwo` è un'istanza di `Pair<String>`, che è conforme a `TitledLoggable` perché `String` è conforme a `TitledLoggable`. Quando il metodo `log()` viene chiamato direttamente su `oneAndTwo`, viene usata la versione specializzata che contiene la stringa del titolo.

```swift
let oneAndTwo = Pair(first: "one", second: "two")
oneAndTwo.log()
// Stampa "Pair of 'String': (one, two)".
```

Tuttavia, quando `oneAndTwo` viene usato in un contesto generico o come istanza del protocollo `Loggable`, la versione specializzata non viene usata. Swift sceglie quale implementazione di `log()` chiamare consultando solo i requisiti minimi di cui `Pair` ha bisogno per essere conforme a `Loggable`. Per questo motivo, viene usata invece l'implementazione predefinita fornita dal protocollo `Loggable`.

```swift
func doSomething<T: Loggable>(with x: T) {
    x.log()
}
doSomething(with: oneAndTwo)
// Stampa "(one, two)".
```

Quando `log()` viene chiamato sull'istanza passata a `doSomething(_:)`, il titolo personalizzato viene omesso dalla stringa registrata.

### La conformità a un protocollo non deve essere ridondante <a href="#la-conformita-a-un-protocollo-non-deve-essere-ridondante" id="la-conformita-a-un-protocollo-non-deve-essere-ridondante"></a>

Un tipo concreto può essere conforme a un particolare protocollo una sola volta. Swift segnala come errore le conformità ridondanti a un protocollo. È probabile che tu incontri questo tipo di errore in due tipi di situazioni. La prima situazione è quando rendi esplicitamente conforme lo stesso protocollo più volte, ma con requisiti diversi. La seconda situazione è quando erediti implicitamente dallo stesso protocollo più volte. Queste situazioni sono discusse nelle sezioni seguenti.

#### Risolvere la ridondanza esplicita <a href="#risolvere-la-ridondanza-esplicita" id="risolvere-la-ridondanza-esplicita"></a>

Più estensioni di un tipo concreto non possono aggiungere la conformità allo stesso protocollo, anche se i requisiti delle estensioni si escludono a vicenda. Questa restrizione è dimostrata nell'esempio seguente. Due dichiarazioni di estensione tentano di aggiungere la conformità condizionale al protocollo `Serializable`, una per gli array con elementi `Int`, e una per gli array con elementi `String`.

```swift
protocol Serializable {
    func serialize() -> Any
}

extension Array: Serializable where Element == Int {
    func serialize() -> Any {
        // implementazione
    }
}
extension Array: Serializable where Element == String {
    func serialize() -> Any {
        // implementazione
    }
}
// Errore: conformità ridondante di 'Array<Element>' al protocollo 'Serializable'.
```

Se devi aggiungere una conformità condizionale basata su più tipi concreti, crea un nuovo protocollo a cui ciascun tipo possa essere conforme e usa quel protocollo come requisito quando dichiari la conformità condizionale.

```swift
protocol SerializableInArray { }
extension Int: SerializableInArray { }
extension String: SerializableInArray { }

extension Array: Serializable where Element: SerializableInArray {
    func serialize() -> Any {
        // implementazione
    }
}
```

#### Risolvere la ridondanza implicita <a href="#risolvere-la-ridondanza-implicita" id="risolvere-la-ridondanza-implicita"></a>

Quando un tipo concreto è condizionalmente conforme a un protocollo, quel tipo è implicitamente conforme a tutti i protocolli genitori con gli stessi requisiti.

Se hai bisogno che un tipo sia condizionalmente conforme a due protocolli che ereditano da un unico genitore, dichiara esplicitamente la conformità al protocollo genitore. Ciò evita di essere implicitamente conformi al protocollo genitore due volte con requisiti diversi.

L'esempio seguente dichiara esplicitamente la conformità condizionale di `Array` a `Loggable` per evitare un conflitto quando si dichiara la sua conformità condizionale sia a `TitledLoggable` sia al nuovo protocollo `MarkedLoggable`.

```swift
protocol MarkedLoggable: Loggable {
    func markAndLog()
}

extension MarkedLoggable {
    func markAndLog() {
        print("----------")
        log()
    }
}

extension Array: Loggable where Element: Loggable { }
extension Array: TitledLoggable where Element: TitledLoggable {
    static var logTitle: String {
        return "Array of '\(Element.logTitle)'"
    }
}
extension Array: MarkedLoggable where Element: MarkedLoggable { }
```

Senza l'estensione che dichiara esplicitamente la conformità condizionale a `Loggable`, le altre estensioni di `Array` creerebbero implicitamente queste dichiarazioni, causando un errore:

```swift
extension Array: Loggable where Element: TitledLoggable { }
extension Array: Loggable where Element: MarkedLoggable { }
// Errore: conformità ridondante di 'Array<Element>' al protocollo 'Loggable'.
```

{% hint style="info" %}
**Grammatica di una dichiarazione di estensione:**

*extension-declaration* → *attributes?* *access-level-modifier?* **`extension`** *type-identifier* *type-inheritance-clause?* *generic-where-clause?* *extension-body*\
*extension-body* → **`{`** *extension-members?* **`}`**

*extension-members* → *extension-member* *extension-members?*\
*extension-member* → *declaration* | *compiler-control-statement*
{% endhint %}

## Dichiarazione di subscript <a href="#dichiarazione-di-subscript" id="dichiarazione-di-subscript"></a>

Una dichiarazione di *subscript* ti permette di aggiungere il supporto per il subscripting agli oggetti di un tipo particolare, ed è in genere usata per fornire una sintassi comoda per accedere agli elementi di una collezione, di una lista o di una sequenza. Le dichiarazioni di subscript si dichiarano usando la parola chiave `subscript` e hanno la forma seguente:

```swift
subscript (<#parameters#>) -> <#return type#> {
   get {
      <#statements#>
   }
   set(<#setter name#>) {
      <#statements#>
   }
}
```

Le dichiarazioni di subscript possono comparire solo nel contesto della dichiarazione di una classe, di una struttura, di un'enumerazione, di un'estensione o di un protocollo.

I *parameters* specificano uno o più indici usati per accedere agli elementi del tipo corrispondente in un'espressione subscript (per esempio, la `i` nell'espressione `object[i]`). Sebbene gli indici usati per accedere agli elementi possano essere di qualsiasi tipo, ogni parametro deve includere un'annotazione di tipo per specificare il tipo di ciascun indice. Il *return type* (tipo di ritorno) specifica il tipo dell'elemento a cui si accede.

Come per le proprietà calcolate, le dichiarazioni di subscript supportano la lettura e la scrittura del valore degli elementi a cui si accede. Il getter è usato per leggere il valore, e il setter è usato per scrivere il valore. La clausola setter è facoltativa, e quando serve solo un getter, puoi omettere entrambe le clausole e restituire semplicemente il valore richiesto in modo diretto. Detto questo, se fornisci una clausola setter, devi fornire anche una clausola getter.

Il *setter name* e le parentesi che lo racchiudono sono facoltativi. Se fornisci un nome del setter, viene usato come nome del parametro del setter. Se non fornisci un nome del setter, il nome predefinito del parametro del setter è `newValue`. Il tipo del parametro del setter è lo stesso del *return type*.

Puoi eseguire l'overload di una dichiarazione di subscript nel tipo in cui è dichiarata, purché i *parameters* o il *return type* differiscano da quelli della dichiarazione di cui esegui l'overload. Puoi anche eseguire l'override di una dichiarazione di subscript ereditata da una superclasse. Quando lo fai, devi contrassegnare la dichiarazione di subscript sottoposta a override con il modificatore di dichiarazione `override`.

I parametri dei subscript seguono le stesse regole dei parametri delle funzioni, con due eccezioni. Per impostazione predefinita, i parametri usati nel subscripting non hanno etichette dell'argomento, a differenza di funzioni, metodi e inizializzatori. Tuttavia, puoi fornire etichette dell'argomento esplicite usando la stessa sintassi usata da funzioni, metodi e inizializzatori. Inoltre, i subscript non possono avere parametri in-out. Un parametro di un subscript può avere un valore predefinito, usando la sintassi descritta in [Tipi speciali di parametri](/riferimento-del-linguaggio/dichiarazioni.md#tipi-speciali-di-parametri).

Puoi anche dichiarare subscript nel contesto della dichiarazione di un protocollo, come descritto in [Dichiarazione di subscript di un protocollo](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-subscript-di-un-protocollo).

Per maggiori informazioni sul subscripting e per vedere esempi di dichiarazioni di subscript, vedi [Subscript](/guida-al-linguaggio/subscript.md).

### Dichiarazioni di subscript di tipo <a href="#dichiarazioni-di-subscript-di-tipo" id="dichiarazioni-di-subscript-di-tipo"></a>

Per dichiarare un subscript esposto dal tipo, anziché dalle istanze del tipo, contrassegna la dichiarazione del subscript con il modificatore di dichiarazione `static`. Le classi possono invece contrassegnare le proprietà calcolate di tipo con il modificatore di dichiarazione `class` per consentire alle sottoclassi di eseguire l'override dell'implementazione della superclasse. Nella dichiarazione di una classe, la parola chiave `static` ha lo stesso effetto del contrassegnare la dichiarazione con entrambi i modificatori di dichiarazione `class` e `final`.

{% hint style="info" %}
**Grammatica di una dichiarazione di subscript:**

*subscript-declaration* → *subscript-head* *subscript-result* *generic-where-clause?* *code-block*\
*subscript-declaration* → *subscript-head* *subscript-result* *generic-where-clause?* *getter-setter-block*\
*subscript-declaration* → *subscript-head* *subscript-result* *generic-where-clause?* *getter-setter-keyword-block*\
*subscript-head* → *attributes?* *declaration-modifiers?* **`subscript`** *generic-parameter-clause?* *parameter-clause*\
*subscript-result* → **`->`** *attributes?* *type*
{% endhint %}

## Dichiarazione di macro <a href="#dichiarazione-di-macro" id="dichiarazione-di-macro"></a>

Una *dichiarazione di macro* introduce una nuova macro. Inizia con la parola chiave `macro` e ha la forma seguente:

```swift
macro <#name#> = <#macro implementation#>
```

La *macro implementation* (implementazione della macro) è un'altra macro, e indica la posizione del codice che esegue l'espansione di questa macro. Il codice che esegue l'espansione della macro è un programma Swift separato, che usa il modulo [SwiftSyntax](https://github.com/swiftlang/swift-syntax) per interagire con il codice Swift. Chiama la macro `externalMacro(module:type:)` della libreria standard di Swift, passandole il nome di un tipo che contiene l'implementazione della macro e il nome del modulo che contiene quel tipo.

Le macro possono essere sottoposte a overload, seguendo lo stesso modello usato dalle funzioni. Una dichiarazione di macro compare solo nell'ambito di file.

Per una panoramica delle macro in Swift, vedi [Macro](/guida-al-linguaggio/macro.md).

{% hint style="info" %}
**Grammatica di una dichiarazione di macro:**

*macro-declaration* → *macro-head* *identifier* *generic-parameter-clause?* *macro-signature* *macro-definition?* *generic-where-clause*\
*macro-head* → *attributes?* *declaration-modifiers?* **`macro`**\
*macro-signature* → *parameter-clause* *macro-function-signature-result?*\
*macro-function-signature-result* → **`->`** *type*\
*macro-definition* → **`=`** *expression*
{% endhint %}

## Dichiarazione di operatore <a href="#dichiarazione-di-operatore" id="dichiarazione-di-operatore"></a>

Una *dichiarazione di operatore* introduce nel tuo programma un nuovo operatore infisso, prefisso o postfisso e si dichiara usando la parola chiave `operator`.

Puoi dichiarare operatori di tre diverse fissità: infissa, prefissa e postfissa. La *fissità* di un operatore specifica la posizione relativa di un operatore rispetto ai suoi operandi.

Esistono tre forme di base di dichiarazione di operatore, una per ciascuna fissità. La fissità dell'operatore si specifica contrassegnando la dichiarazione dell'operatore con il modificatore di dichiarazione `infix`, `prefix` o `postfix` prima della parola chiave `operator`. In ciascuna forma, il nome dell'operatore può contenere solo i caratteri degli operatori definiti in [Operatori](/riferimento-del-linguaggio/struttura-lessicale.md#operatori).

La forma seguente dichiara un nuovo operatore infisso:

```swift
infix operator <#operator name#>: <#precedence group#>
```

Un *operatore infisso* è un operatore binario scritto tra i suoi due operandi, come il familiare operatore di addizione (`+`) nell'espressione `1 + 2`.

Gli operatori infissi possono facoltativamente specificare un gruppo di precedenza. Se ometti il gruppo di precedenza di un operatore, Swift usa il gruppo di precedenza predefinito, `DefaultPrecedence`, che specifica una precedenza appena superiore a `TernaryPrecedence`. Per maggiori informazioni, vedi [Dichiarazione di gruppo di precedenza](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-gruppo-di-precedenza).

La forma seguente dichiara un nuovo operatore prefisso:

```swift
prefix operator <#operator name#>
```

Un *operatore prefisso* è un operatore unario scritto immediatamente prima del suo operando, come l'operatore logico NOT prefisso (`!`) nell'espressione `!a`.

Le dichiarazioni di operatori prefissi non specificano un livello di precedenza. Gli operatori prefissi sono non associativi.

La forma seguente dichiara un nuovo operatore postfisso:

```swift
postfix operator <#operator name#>
```

Un *operatore postfisso* è un operatore unario scritto immediatamente dopo il suo operando, come l'operatore postfisso di unwrapping forzato (`!`) nell'espressione `a!`.

Come per gli operatori prefissi, le dichiarazioni di operatori postfissi non specificano un livello di precedenza. Gli operatori postfissi sono non associativi.

Dopo aver dichiarato un nuovo operatore, lo implementi dichiarando un metodo statico che ha lo stesso nome dell'operatore. Il metodo statico è un membro di uno dei tipi i cui valori l'operatore accetta come argomento — per esempio, un operatore che moltiplica un `Double` per un `Int` è implementato come metodo statico della struttura `Double` o della struttura `Int`. Se stai implementando un operatore prefisso o postfisso, devi anche contrassegnare la dichiarazione di quel metodo con il modificatore di dichiarazione `prefix` o `postfix` corrispondente. Per vedere un esempio di come creare e implementare un nuovo operatore, vedi [Operatori personalizzati](/guida-al-linguaggio/operatori-avanzati.md#operatori-personalizzati).

{% hint style="info" %}
**Grammatica di una dichiarazione di operatore:**

*operator-declaration* → *prefix-operator-declaration* | *postfix-operator-declaration* | *infix-operator-declaration*

*prefix-operator-declaration* → **`prefix`** **`operator`** *operator*\
*postfix-operator-declaration* → **`postfix`** **`operator`** *operator*\
*infix-operator-declaration* → **`infix`** **`operator`** *operator* *infix-operator-group?*

*infix-operator-group* → **`:`** *precedence-group-name*
{% endhint %}

## Dichiarazione di gruppo di precedenza <a href="#dichiarazione-di-gruppo-di-precedenza" id="dichiarazione-di-gruppo-di-precedenza"></a>

Una *dichiarazione di gruppo di precedenza* introduce nel tuo programma un nuovo raggruppamento per la precedenza degli operatori infissi. La precedenza di un operatore specifica quanto strettamente l'operatore si lega ai suoi operandi, in assenza di parentesi di raggruppamento.

Una dichiarazione di gruppo di precedenza ha la forma seguente:

```swift
precedencegroup <#precedence group name#> {
    higherThan: <#lower group names#>
    lowerThan: <#higher group names#>
    associativity: <#associativity#>
    assignment: <#assignment#>
}
```

Gli elenchi *lower group names* (nomi dei gruppi inferiori) e *higher group names* (nomi dei gruppi superiori) specificano la relazione del nuovo gruppo di precedenza con i gruppi di precedenza esistenti. L'attributo di gruppo di precedenza `lowerThan` può essere usato solo per fare riferimento a gruppi di precedenza dichiarati al di fuori del modulo corrente. Quando due operatori competono tra loro per i propri operandi, come nell'espressione `2 + 3 * 5`, l'operatore con la precedenza relativa più alta si lega più strettamente ai suoi operandi.

{% hint style="info" %}
**Nota:** I gruppi di precedenza messi in relazione tra loro usando *lower group names* e *higher group names* devono rientrare in un'unica gerarchia relazionale, ma *non* devono necessariamente formare una gerarchia lineare. Ciò significa che è possibile avere gruppi di precedenza con precedenza relativa indefinita. Gli operatori di quei gruppi di precedenza non possono essere usati l'uno accanto all'altro senza parentesi di raggruppamento.
{% endhint %}

Swift definisce numerosi gruppi di precedenza da abbinare agli operatori forniti dalla libreria standard di Swift. Per esempio, gli operatori di addizione (`+`) e sottrazione (`-`) appartengono al gruppo `AdditionPrecedence`, e gli operatori di moltiplicazione (`*`) e divisione (`/`) appartengono al gruppo `MultiplicationPrecedence`. Per un elenco completo dei gruppi di precedenza forniti dalla libreria standard di Swift, vedi [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations).

L'*associatività* di un operatore specifica come una sequenza di operatori con lo stesso livello di precedenza viene raggruppata in assenza di parentesi di raggruppamento. Specifichi l'associatività di un operatore scrivendo una delle parole chiave contestuali `left`, `right` o `none` — se ometti l'associatività, il valore predefinito è `none`. Gli operatori associativi a sinistra raggruppano da sinistra a destra. Per esempio, l'operatore di sottrazione (`-`) è associativo a sinistra, quindi l'espressione `4 - 5 - 6` viene raggruppata come `(4 - 5) - 6` e restituisce `-7`. Gli operatori associativi a destra raggruppano da destra a sinistra, e gli operatori specificati con un'associatività `none` non si associano affatto. Gli operatori non associativi con lo stesso livello di precedenza non possono comparire adiacenti l'uno all'altro. Per esempio, l'operatore `<` ha un'associatività `none`, il che significa che `1 < 2 < 3` non è un'espressione valida.

L'*assignment* (assegnazione) di un gruppo di precedenza specifica la precedenza di un operatore quando viene usato in un'operazione che include l'optional chaining. Quando è impostato a `true`, un operatore del gruppo di precedenza corrispondente usa durante l'optional chaining le stesse regole di raggruppamento degli operatori di assegnazione della libreria standard di Swift. Altrimenti, quando è impostato a `false` o omesso, gli operatori del gruppo di precedenza seguono le stesse regole di optional chaining degli operatori che non eseguono assegnazioni.

{% hint style="info" %}
**Grammatica di una dichiarazione di gruppo di precedenza:**

*precedence-group-declaration* → **`precedencegroup`** *precedence-group-name* **`{`** *precedence-group-attributes?* **`}`**

*precedence-group-attributes* → *precedence-group-attribute* *precedence-group-attributes?*\
*precedence-group-attribute* → *precedence-group-relation*\
*precedence-group-attribute* → *precedence-group-assignment*\
*precedence-group-attribute* → *precedence-group-associativity*

*precedence-group-relation* → **`higherThan`** **`:`** *precedence-group-names*\
*precedence-group-relation* → **`lowerThan`** **`:`** *precedence-group-names*

*precedence-group-assignment* → **`assignment`** **`:`** *boolean-literal*

*precedence-group-associativity* → **`associativity`** **`:`** **`left`**\
*precedence-group-associativity* → **`associativity`** **`:`** **`right`**\
*precedence-group-associativity* → **`associativity`** **`:`** **`none`**

*precedence-group-names* → *precedence-group-name* | *precedence-group-name* **`,`** *precedence-group-names*\
*precedence-group-name* → *identifier*
{% endhint %}

## Modificatori di dichiarazione <a href="#modificatori-di-dichiarazione" id="modificatori-di-dichiarazione"></a>

I *modificatori di dichiarazione* sono parole chiave o parole chiave contestuali che modificano il comportamento o il significato di una dichiarazione. Specifichi un modificatore di dichiarazione scrivendo la parola chiave o la parola chiave contestuale appropriata tra gli attributi di una dichiarazione (se presenti) e la parola chiave che introduce la dichiarazione.

* **`class`**: Applica questo modificatore a un membro di una classe per indicare che il membro è un membro della classe stessa, anziché un membro delle istanze della classe. I membri di una superclasse che hanno questo modificatore e non hanno il modificatore `final` possono essere sottoposti a override dalle sottoclassi.
* **`dynamic`**: Applica questo modificatore a qualsiasi membro di una classe che possa essere rappresentato da Objective-C. Quando contrassegni la dichiarazione di un membro con il modificatore `dynamic`, l'accesso a quel membro viene sempre inviato dinamicamente usando il runtime di Objective-C. L'accesso a quel membro non viene mai reso inline né devirtualizzato dal compilatore.

  Poiché le dichiarazioni contrassegnate con il modificatore `dynamic` vengono inviate usando il runtime di Objective-C, devono essere contrassegnate con l'attributo `objc`.
* **`final`**: Applica questo modificatore a una classe o a un membro proprietà, metodo o subscript di una classe. Si applica a una classe per indicare che dalla classe non si possono derivare sottoclassi. Si applica a una proprietà, a un metodo o a un subscript di una classe per indicare che un membro della classe non può essere sottoposto a override in alcuna sottoclasse. Per un esempio di come usare l'attributo `final`, vedi [Impedire gli override](/guida-al-linguaggio/ereditarieta.md#impedire-gli-override).
* **`lazy`**: Applica questo modificatore a una proprietà variabile memorizzata di una classe o di una struttura per indicare che il valore iniziale della proprietà viene calcolato e memorizzato al massimo una volta, quando si accede alla proprietà per la prima volta. Per un esempio di come usare il modificatore `lazy`, vedi [Proprietà memorizzate lazy](/guida-al-linguaggio/proprieta.md#proprieta-memorizzate-lazy).
* **`optional`**: Applica questo modificatore ai membri proprietà, metodo o subscript di un protocollo per indicare che un tipo conforme non è tenuto a implementare quei membri.

  Puoi applicare il modificatore `optional` solo ai protocolli contrassegnati con l'attributo `objc`. Di conseguenza, solo i tipi classe possono adottare ed essere conformi a un protocollo che contiene requisiti di membri facoltativi. Per maggiori informazioni su come usare il modificatore `optional` e per indicazioni su come accedere ai membri facoltativi di un protocollo — per esempio, quando non sei sicuro che un tipo conforme li implementi — vedi [Requisiti opzionali dei protocolli](/guida-al-linguaggio/protocolli.md#requisiti-opzionali-dei-protocolli).
* **`required`**: Applica questo modificatore a un inizializzatore designato o di convenienza di una classe per indicare che ogni sottoclasse deve implementare quell'inizializzatore. Anche l'implementazione di quell'inizializzatore nella sottoclasse deve essere contrassegnata con il modificatore `required`.
* **`static`**: Applica questo modificatore a un membro di una struttura, di una classe, di un'enumerazione o di un protocollo per indicare che il membro è un membro del tipo, anziché un membro delle istanze di quel tipo. Nell'ambito della dichiarazione di una classe, scrivere il modificatore `static` sulla dichiarazione di un membro ha lo stesso effetto di scrivere i modificatori `class` e `final` sulla dichiarazione di quel membro. Tuttavia, le proprietà di tipo costanti di una classe costituiscono un'eccezione: lì `static` ha il suo normale significato, non legato alle classi, perché non puoi scrivere `class` o `final` su quelle dichiarazioni.
* **`unowned`**: Applica questo modificatore a una variabile memorizzata, a una costante o a una proprietà memorizzata per indicare che la variabile o la proprietà ha un riferimento unowned all'oggetto memorizzato come suo valore. Se tenti di accedere alla variabile o alla proprietà dopo che l'oggetto è stato deallocato, viene generato un errore in fase di esecuzione. Come per un riferimento weak, il tipo della proprietà o del valore deve essere un tipo classe; a differenza di un riferimento weak, il tipo non è opzionale. Per un esempio e maggiori informazioni sul modificatore `unowned`, vedi [Riferimenti unowned](/guida-al-linguaggio/conteggio-automatico-dei-riferimenti.md#riferimenti-unowned).
* **`unowned(safe)`**: Una scrittura esplicita di `unowned`.
* **`unowned(unsafe)`**: Applica questo modificatore a una variabile memorizzata, a una costante o a una proprietà memorizzata per indicare che la variabile o la proprietà ha un riferimento unowned all'oggetto memorizzato come suo valore. Se tenti di accedere alla variabile o alla proprietà dopo che l'oggetto è stato deallocato, accederai alla memoria nella posizione in cui si trovava l'oggetto, il che è un'operazione non sicura per la memoria. Come per un riferimento weak, il tipo della proprietà o del valore deve essere un tipo classe; a differenza di un riferimento weak, il tipo non è opzionale. Per un esempio e maggiori informazioni sul modificatore `unowned`, vedi [Riferimenti unowned](/guida-al-linguaggio/conteggio-automatico-dei-riferimenti.md#riferimenti-unowned).
* **`weak`**: Applica questo modificatore a una variabile memorizzata o a una proprietà variabile memorizzata per indicare che la variabile o la proprietà ha un riferimento weak all'oggetto memorizzato come suo valore. Il tipo della variabile o della proprietà deve essere un tipo classe opzionale. Se accedi alla variabile o alla proprietà dopo che l'oggetto è stato deallocato, il suo valore è `nil`. Per un esempio e maggiori informazioni sul modificatore `weak`, vedi [Riferimenti weak](/guida-al-linguaggio/conteggio-automatico-dei-riferimenti.md#riferimenti-weak).

### Livelli di controllo degli accessi <a href="#livelli-di-controllo-degli-accessi" id="livelli-di-controllo-degli-accessi"></a>

Swift fornisce cinque livelli di controllo degli accessi: open, public, internal, file private e private. Puoi contrassegnare una dichiarazione con uno dei modificatori di livello di accesso seguenti per specificare il livello di accesso della dichiarazione. Il controllo degli accessi è trattato in dettaglio in [Controllo degli accessi](/guida-al-linguaggio/controllo-degli-accessi.md).

* **`open`**: Applica questo modificatore a una dichiarazione per indicare che la dichiarazione è accessibile e può essere sottoclassata dal codice nello stesso modulo della dichiarazione. Le dichiarazioni contrassegnate con il modificatore di livello di accesso `open` sono anche accessibili e possono essere sottoclassate dal codice in un modulo che importa il modulo che contiene quella dichiarazione.
* **`public`**: Applica questo modificatore a una dichiarazione per indicare che la dichiarazione è accessibile e può essere sottoclassata dal codice nello stesso modulo della dichiarazione. Le dichiarazioni contrassegnate con il modificatore di livello di accesso `public` sono anche accessibili (ma non possono essere sottoclassate) dal codice in un modulo che importa il modulo che contiene quella dichiarazione.
* **`package`**: Applica questo modificatore a una dichiarazione per indicare che la dichiarazione è accessibile solo dal codice nello stesso package della dichiarazione. Un package è un'unità di distribuzione del codice che definisci nel sistema di build che stai usando. Quando il sistema di build compila il codice, specifica il nome del package passando il flag `-package-name` al compilatore Swift. Due moduli fanno parte dello stesso package se il sistema di build specifica lo stesso nome di package quando li compila.
* **`internal`**: Applica questo modificatore a una dichiarazione per indicare che la dichiarazione è accessibile solo dal codice nello stesso modulo della dichiarazione. Per impostazione predefinita, la maggior parte delle dichiarazioni è contrassegnata implicitamente con il modificatore di livello di accesso `internal`.
* **`fileprivate`**: Applica questo modificatore a una dichiarazione per indicare che la dichiarazione è accessibile solo dal codice nello stesso file sorgente della dichiarazione.
* **`private`**: Applica questo modificatore a una dichiarazione per indicare che la dichiarazione è accessibile solo dal codice all'interno dell'ambito che racchiude immediatamente la dichiarazione.

Ai fini del controllo degli accessi, le estensioni si comportano come segue:

* Se ci sono più estensioni nello stesso file, e quelle estensioni estendono tutte lo stesso tipo, allora tutte quelle estensioni hanno lo stesso ambito di controllo degli accessi. Le estensioni e il tipo che estendono possono trovarsi in file diversi.
* Se ci sono estensioni nello stesso file del tipo che estendono, le estensioni hanno lo stesso ambito di controllo degli accessi del tipo che estendono.
* I membri privati dichiarati nella dichiarazione di un tipo sono accessibili dalle estensioni di quel tipo. I membri privati dichiarati in un'estensione sono accessibili dalle altre estensioni e dalla dichiarazione del tipo esteso.

Ciascuno dei modificatori di livello di accesso qui sopra accetta facoltativamente un singolo argomento, costituito dalla parola chiave `set` racchiusa tra parentesi — per esempio, `private(set)`. Usa questa forma di modificatore di livello di accesso quando vuoi specificare un livello di accesso per il setter di una variabile o di un subscript che sia inferiore o uguale al livello di accesso della variabile o del subscript stesso, come discusso in [Getter e setter](/guida-al-linguaggio/controllo-degli-accessi.md#getter-e-setter).

{% hint style="info" %}
**Grammatica di un modificatore di dichiarazione:**

*declaration-modifier* → **`class`** | **`convenience`** | **`dynamic`** | **`final`** | **`infix`** | **`lazy`** | **`optional`** | **`override`** | **`postfix`** | **`prefix`** | **`required`** | **`static`** | **`unowned`** | **`unowned`** **`(`** **`safe`** **`)`** | **`unowned`** **`(`** **`unsafe`** **`)`** | **`weak`**\
*declaration-modifier* → *access-level-modifier*\
*declaration-modifier* → *mutation-modifier*\
*declaration-modifier* → *actor-isolation-modifier*\
*declaration-modifiers* → *declaration-modifier* *declaration-modifiers?*

*access-level-modifier* → **`private`** | **`private`** **`(`** **`set`** **`)`**\
*access-level-modifier* → **`fileprivate`** | **`fileprivate`** **`(`** **`set`** **`)`**\
*access-level-modifier* → **`internal`** | **`internal`** **`(`** **`set`** **`)`**\
*access-level-modifier* → **`package`** | **`package`** **`(`** **`set`** **`)`**\
*access-level-modifier* → **`public`** | **`public`** **`(`** **`set`** **`)`**\
*access-level-modifier* → **`open`** | **`open`** **`(`** **`set`** **`)`**

*mutation-modifier* → **`mutating`** | **`nonmutating`**

*actor-isolation-modifier* → **`nonisolated`**
{% endhint %}
