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

# Estensioni (Extensions)

Aggiungi funzionalità a un tipo esistente.

Le *estensioni* aggiungono nuove funzionalità a un tipo esistente, che sia una classe, una struttura, un'enumerazione o un protocollo. Ciò include la possibilità di estendere tipi di cui non hai accesso al codice sorgente originale (nota come *modellazione retroattiva*). Le estensioni sono simili alle categorie di Objective-C. (A differenza delle categorie di Objective-C, le estensioni di Swift non hanno nomi.)

In Swift le estensioni possono:

* Aggiungere proprietà calcolate di istanza e proprietà calcolate di tipo
* Definire metodi di istanza e metodi di tipo
* Fornire nuovi inizializzatori
* Definire subscript
* Definire e usare nuovi tipi annidati
* Rendere un tipo esistente conforme a un protocollo

In Swift, puoi persino estendere un protocollo per fornire implementazioni dei suoi requisiti o aggiungere funzionalità supplementari di cui i tipi conformi possono avvalersi. Per maggiori dettagli, vedi [Estensioni dei protocolli](/guida-al-linguaggio/protocolli.md#estensioni-dei-protocolli).

{% hint style="info" %}
**Nota:** Le estensioni possono aggiungere nuove funzionalità a un tipo, ma non possono sovrascrivere funzionalità esistenti.
{% endhint %}

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

Dichiara le estensioni con la parola chiave `extension`:

```swift
extension SomeType {
    // qui va la nuova funzionalità da aggiungere a SomeType
}
```

Un'estensione può estendere un tipo esistente per fargli adottare uno o più protocolli. Per aggiungere la conformità a un protocollo, scrivi i nomi dei protocolli nello stesso modo in cui li scrivi per una classe o una struttura:

```swift
extension SomeType: SomeProtocol, AnotherProtocol {
    // qui va l'implementazione dei requisiti del protocollo
}
```

L'aggiunta della conformità a un protocollo in questo modo è descritta in [Aggiungere la conformità a un protocollo con un'estensione](/guida-al-linguaggio/protocolli.md#aggiungere-la-conformita-a-un-protocollo-con-unestensione).

Un'estensione può essere usata per estendere un tipo generico esistente, come descritto in [Estendere un tipo generico](/guida-al-linguaggio/generici.md#estendere-un-tipo-generico). Puoi anche estendere un tipo generico per aggiungere funzionalità in modo condizionale, come descritto in [Estensioni con una clausola where generica](/guida-al-linguaggio/generici.md#estensioni-con-una-clausola-where-generica).

{% hint style="info" %}
**Nota:** Se definisci un'estensione per aggiungere nuove funzionalità a un tipo esistente, le nuove funzionalità saranno disponibili su tutte le istanze esistenti di quel tipo, anche se sono state create prima che l'estensione fosse definita.
{% endhint %}

## Proprietà calcolate <a href="#proprieta-calcolate" id="proprieta-calcolate"></a>

Le estensioni possono aggiungere proprietà calcolate di istanza e proprietà calcolate di tipo ai tipi esistenti. Questo esempio aggiunge cinque proprietà calcolate di istanza al tipo `Double` integrato di Swift, per fornire un supporto di base al lavoro con le unità di distanza:

```swift
extension Double {
    var km: Double { return self * 1_000.0 }
    var m: Double { return self }
    var cm: Double { return self / 100.0 }
    var mm: Double { return self / 1_000.0 }
    var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
print("One inch is \(oneInch) meters")
// Stampa "One inch is 0.0254 meters".
let threeFeet = 3.ft
print("Three feet is \(threeFeet) meters")
// Stampa "Three feet is 0.914399970739201 meters".
```

Queste proprietà calcolate esprimono che un valore `Double` deve essere considerato come una certa unità di lunghezza. Sebbene siano implementate come proprietà calcolate, i nomi di queste proprietà possono essere accodati a un valore letterale in virgola mobile con la sintassi a punto, come modo per usare quel valore letterale per eseguire conversioni di distanza.

In questo esempio, si considera che un valore `Double` di `1.0` rappresenti “un metro”. Ecco perché la proprietà calcolata `m` restituisce `self` — si considera che l'espressione `1.m` calcoli un valore `Double` di `1.0`.

Le altre unità richiedono una certa conversione per essere espresse come valore misurato in metri. Un chilometro equivale a 1.000 metri, quindi la proprietà calcolata `km` moltiplica il valore per `1_000.00` per convertirlo in un numero espresso in metri. Analogamente, in un metro ci sono 3,28084 piedi, e quindi la proprietà calcolata `ft` divide il valore `Double` sottostante per `3.28084`, per convertirlo da piedi a metri.

Queste proprietà sono proprietà calcolate di sola lettura, e quindi, per brevità, sono espresse senza la parola chiave `get`. Il loro valore di ritorno è di tipo `Double`, e può essere usato nei calcoli matematici ovunque sia accettato un `Double`:

```swift
let aMarathon = 42.km + 195.m
print("A marathon is \(aMarathon) meters long")
// Stampa "A marathon is 42195.0 meters long".
```

{% hint style="info" %}
**Nota:** Le estensioni possono aggiungere nuove proprietà calcolate, ma non possono aggiungere proprietà memorizzate, né aggiungere osservatori di proprietà alle proprietà esistenti.
{% endhint %}

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

Le estensioni possono aggiungere nuovi inizializzatori ai tipi esistenti. Questo ti permette di estendere altri tipi affinché accettino i tuoi tipi personalizzati come parametri dell'inizializzatore, o di fornire opzioni di inizializzazione aggiuntive che non erano incluse nell'implementazione originale del tipo.

Le estensioni possono aggiungere nuovi inizializzatori di convenienza a una classe, ma non possono aggiungere a una classe nuovi inizializzatori designati o deinizializzatori. Gli inizializzatori designati e i deinizializzatori devono sempre essere forniti dall'implementazione originale della classe.

Se usi un'estensione per aggiungere un inizializzatore a un tipo valore che fornisce valori predefiniti per tutte le sue proprietà memorizzate e non definisce alcun inizializzatore personalizzato, puoi chiamare l'inizializzatore predefinito e l'inizializzatore memberwise di quel tipo valore dall'interno dell'inizializzatore della tua estensione. Questo non sarebbe il caso se avessi scritto l'inizializzatore come parte dell'implementazione originale del tipo valore, come descritto in [Delega degli inizializzatori per i tipi valore](/guida-al-linguaggio/inizializzazione.md#delega-degli-inizializzatori-per-i-tipi-valore).

Se usi un'estensione per aggiungere un inizializzatore a una struttura dichiarata in un altro modulo, il nuovo inizializzatore non può accedere a `self` finché non chiama un inizializzatore del modulo che la definisce.

L'esempio seguente definisce una struttura personalizzata `Rect` per rappresentare un rettangolo geometrico. L'esempio definisce anche due strutture di supporto chiamate `Size` e `Point`, che forniscono entrambe valori predefiniti di `0.0` per tutte le loro proprietà:

```swift
struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()
}
```

Poiché la struttura `Rect` fornisce valori predefiniti per tutte le sue proprietà, riceve automaticamente un inizializzatore predefinito e un inizializzatore memberwise, come descritto in [Inizializzatori predefiniti](/guida-al-linguaggio/inizializzazione.md#inizializzatori-predefiniti). Questi inizializzatori possono essere usati per creare nuove istanze di `Rect`:

```swift
let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
    size: Size(width: 5.0, height: 5.0))
```

Puoi estendere la struttura `Rect` per fornire un inizializzatore aggiuntivo che accetti un punto centrale e una dimensione specifici:

```swift
extension Rect {
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}
```

Questo nuovo inizializzatore inizia calcolando un punto di origine appropriato in base al punto `center` e al valore `size` forniti. L'inizializzatore chiama poi l'inizializzatore memberwise automatico della struttura `init(origin:size:)`, che memorizza i nuovi valori di origine e di dimensione nelle proprietà appropriate:

```swift
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
    size: Size(width: 3.0, height: 3.0))
// l'origine di centerRect è (2.5, 2.5) e la sua dimensione è (3.0, 3.0)
```

{% hint style="info" %}
**Nota:** Se fornisci un nuovo inizializzatore con un'estensione, sei comunque responsabile di assicurarti che ogni istanza sia completamente inizializzata una volta che l'inizializzatore è terminato.
{% endhint %}

## Metodi <a href="#metodi" id="metodi"></a>

Le estensioni possono aggiungere nuovi metodi di istanza e metodi di tipo ai tipi esistenti. L'esempio seguente aggiunge un nuovo metodo di istanza chiamato `repetitions` al tipo `Int`:

```swift
extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
        }
    }
}
```

Il metodo `repetitions(task:)` accetta un singolo argomento di tipo `() -> Void`, che indica una funzione che non ha parametri e non restituisce alcun valore.

Dopo aver definito questa estensione, puoi chiamare il metodo `repetitions(task:)` su qualsiasi intero per eseguire un'operazione quel numero di volte:

```swift
3.repetitions {
    print("Hello!")
}
// Hello!
// Hello!
// Hello!
```

### Metodi di istanza mutating <a href="#metodi-di-istanza-mutating" id="metodi-di-istanza-mutating"></a>

I metodi di istanza aggiunti con un'estensione possono anche modificare (o *mutare*) l'istanza stessa. I metodi di strutture ed enumerazioni che modificano `self` o le sue proprietà devono contrassegnare il metodo di istanza come `mutating`, proprio come i metodi mutating di un'implementazione originale.

L'esempio seguente aggiunge un nuovo metodo mutating chiamato `square` al tipo `Int` di Swift, che eleva al quadrato il valore originale:

```swift
extension Int {
    mutating func square() {
        self = self * self
    }
}
var someInt = 3
someInt.square()
// someInt ora vale 9
```

## Subscript <a href="#subscript" id="subscript"></a>

Le estensioni possono aggiungere nuovi subscript a un tipo esistente. Questo esempio aggiunge un subscript intero al tipo `Int` integrato di Swift. Questo subscript `[n]` restituisce la cifra decimale che si trova `n` posizioni a partire dalla destra del numero:

* `123456789[0]` restituisce `9`
* `123456789[1]` restituisce `8`

…e così via:

```swift
extension Int {
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
        for _ in 0..<digitIndex {
            decimalBase *= 10
        }
        return (self / decimalBase) % 10
    }
}
746381295[0]
// restituisce 5
746381295[1]
// restituisce 9
746381295[2]
// restituisce 2
746381295[8]
// restituisce 7
```

Se il valore `Int` non ha abbastanza cifre per l'indice richiesto, l'implementazione del subscript restituisce `0`, come se il numero fosse stato completato con degli zeri a sinistra:

```swift
746381295[9]
// restituisce 0, come se avessi richiesto:
0746381295[9]
```

## Tipi annidati <a href="#tipi-annidati" id="tipi-annidati"></a>

Le estensioni possono aggiungere nuovi tipi annidati a classi, strutture ed enumerazioni esistenti:

```swift
extension Int {
    enum Kind {
        case negative, zero, positive
    }
    var kind: Kind {
        switch self {
        case 0:
            return .zero
        case let x where x > 0:
            return .positive
        default:
            return .negative
        }
    }
}
```

Questo esempio aggiunge una nuova enumerazione annidata a `Int`. Questa enumerazione, chiamata `Kind`, esprime il genere di numero rappresentato da un particolare intero. In particolare, esprime se il numero è negativo, zero o positivo.

Questo esempio aggiunge anche a `Int` una nuova proprietà calcolata di istanza, chiamata `kind`, che restituisce il caso dell'enumerazione `Kind` appropriato per quell'intero.

L'enumerazione annidata può ora essere usata con qualsiasi valore `Int`:

```swift
func printIntegerKinds(_ numbers: [Int]) {
    for number in numbers {
        switch number.kind {
        case .negative:
            print("- ", terminator: "")
        case .zero:
            print("0 ", terminator: "")
        case .positive:
            print("+ ", terminator: "")
        }
    }
    print("")
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
// Stampa "+ + - 0 - 0 + ".
```

Questa funzione, `printIntegerKinds(_:)`, accetta in input un array di valori `Int` e itera su quei valori uno alla volta. Per ciascun intero dell'array, la funzione considera la proprietà calcolata `kind` di quell'intero, e stampa una descrizione appropriata.

{% hint style="info" %}
**Nota:** È già noto che `number.kind` è di tipo `Int.Kind`. Per questo motivo, tutti i valori dei casi di `Int.Kind` possono essere scritti in forma abbreviata all'interno dell'istruzione `switch`, come `.negative` anziché `Int.Kind.negative`.
{% endhint %}
