> 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/operatori-avanzati.md).

# Operatori avanzati (Advanced Operators)

Definisci operatori personalizzati, esegui operazioni bit a bit e usa la sintassi dei builder.

Oltre agli operatori descritti in [Operatori di base](/guida-al-linguaggio/operatori-di-base.md), Swift fornisce diversi operatori avanzati che eseguono manipolazioni di valori più complesse. Questi comprendono tutti gli operatori bit a bit e di scorrimento di bit che conoscerai da C e Objective-C.

A differenza degli operatori aritmetici in C, gli operatori aritmetici in Swift non vanno in overflow per impostazione predefinita. Il comportamento di overflow viene intercettato e segnalato come errore. Per abilitare il comportamento di overflow, usa il secondo insieme di operatori aritmetici di Swift, che vanno in overflow per impostazione predefinita, come l'operatore di addizione con overflow (`&+`). Tutti questi operatori di overflow iniziano con una e commerciale (`&`).

Quando definisci le tue strutture, classi ed enumerazioni, può essere utile fornire le tue implementazioni degli operatori standard di Swift per questi tipi personalizzati. Swift rende facile fornire implementazioni su misura di questi operatori e determinare esattamente quale debba essere il loro comportamento per ciascun tipo che crei.

Non sei limitato agli operatori predefiniti. Swift ti dà la libertà di definire i tuoi operatori personalizzati infissi, prefissi, postfissi e di assegnamento, con valori di precedenza e associatività personalizzati. Questi operatori possono essere usati e adottati nel tuo codice come qualsiasi operatore predefinito, e puoi persino estendere tipi esistenti affinché supportino gli operatori personalizzati che definisci.

## Operatori bit a bit <a href="#operatori-bit-a-bit" id="operatori-bit-a-bit"></a>

Gli *operatori bit a bit* ti permettono di manipolare i singoli bit di dati grezzi all'interno di una struttura dati. Sono spesso usati nella programmazione a basso livello, come la programmazione grafica e la creazione di driver di dispositivo. Gli operatori bit a bit possono essere utili anche quando lavori con dati grezzi provenienti da fonti esterne, come la codifica e la decodifica di dati per la comunicazione tramite un protocollo personalizzato.

Swift supporta tutti gli operatori bit a bit presenti in C, come descritto di seguito.

### Operatore NOT bit a bit <a href="#operatore-not-bit-a-bit" id="operatore-not-bit-a-bit"></a>

L'*operatore NOT bit a bit* (`~`) inverte tutti i bit di un numero:

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

L'operatore NOT bit a bit è un operatore prefisso, e compare immediatamente prima del valore su cui opera, senza alcuno spazio:

```swift
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits  // è uguale a 11110000
```

Gli interi `UInt8` hanno otto bit e possono memorizzare qualsiasi valore tra `0` e `255`. Questo esempio inizializza un intero `UInt8` con il valore binario `00001111`, che ha i primi quattro bit impostati a `0`, e i secondi quattro bit impostati a `1`. Questo equivale a un valore decimale di `15`.

L'operatore NOT bit a bit viene poi usato per creare una nuova costante chiamata `invertedBits`, che è uguale a `initialBits`, ma con tutti i bit invertiti. Gli zeri diventano uno, e gli uno diventano zeri. Il valore di `invertedBits` è `11110000`, che è uguale a un valore decimale senza segno di `240`.

### Operatore AND bit a bit <a href="#operatore-and-bit-a-bit" id="operatore-and-bit-a-bit"></a>

L'*operatore AND bit a bit* (`&`) combina i bit di due numeri. Restituisce un nuovo numero i cui bit sono impostati a `1` solo se i bit erano uguali a `1` in *entrambi* i numeri in input:

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

Nell'esempio seguente, i valori di `firstSixBits` e `lastSixBits` hanno entrambi i quattro bit centrali uguali a `1`. L'operatore AND bit a bit li combina per ottenere il numero `00111100`, che è uguale a un valore decimale senza segno di `60`:

```swift
let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8  = 0b00111111
let middleFourBits = firstSixBits & lastSixBits  // è uguale a 00111100
```

### Operatore OR bit a bit <a href="#operatore-or-bit-a-bit" id="operatore-or-bit-a-bit"></a>

L'*operatore OR bit a bit* (`|`) confronta i bit di due numeri. L'operatore restituisce un nuovo numero i cui bit sono impostati a `1` se i bit sono uguali a `1` in *uno qualsiasi* dei due numeri in input:

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

Nell'esempio seguente, i valori di `someBits` e `moreBits` hanno bit diversi impostati a `1`. L'operatore OR bit a bit li combina per ottenere il numero `11111110`, che equivale a un decimale senza segno di `254`:

```swift
let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits  // è uguale a 11111110
```

### Operatore XOR bit a bit <a href="#operatore-xor-bit-a-bit" id="operatore-xor-bit-a-bit"></a>

L'*operatore XOR bit a bit*, o “operatore OR esclusivo” (`^`), confronta i bit di due numeri. L'operatore restituisce un nuovo numero i cui bit sono impostati a `1` dove i bit in input sono diversi e sono impostati a `0` dove i bit in input sono uguali:

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

Nell'esempio seguente, i valori di `firstBits` e `otherBits` hanno ciascuno un bit impostato a `1` in una posizione in cui l'altro non ce l'ha. L'operatore XOR bit a bit imposta entrambi questi bit a `1` nel suo valore di output. Tutti gli altri bit di `firstBits` e `otherBits` coincidono e sono impostati a `0` nel valore di output:

```swift
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits  // è uguale a 00010001
```

### Operatori di scorrimento bit a bit a sinistra e a destra <a href="#operatori-di-scorrimento-bit-a-bit-a-sinistra-e-a-destra" id="operatori-di-scorrimento-bit-a-bit-a-sinistra-e-a-destra"></a>

L'*operatore di scorrimento bit a bit a sinistra* (`<<`) e l'*operatore di scorrimento bit a bit a destra* (`>>`) spostano tutti i bit di un numero a sinistra o a destra di un certo numero di posizioni, secondo le regole definite di seguito.

Gli scorrimenti bit a bit a sinistra e a destra hanno l'effetto di moltiplicare o dividere un intero per un fattore di due. Scorrere i bit di un intero a sinistra di una posizione ne raddoppia il valore, mentre scorrerli a destra di una posizione lo dimezza.

#### Comportamento dello scorrimento per gli interi senza segno <a href="#comportamento-dello-scorrimento-per-gli-interi-senza-segno" id="comportamento-dello-scorrimento-per-gli-interi-senza-segno"></a>

Il comportamento dello scorrimento di bit per gli interi senza segno è il seguente:

1. I bit esistenti vengono spostati a sinistra o a destra del numero di posizioni richiesto.
2. Tutti i bit spostati oltre i limiti della memoria dell'intero vengono scartati.
3. Vengono inseriti degli zeri negli spazi lasciati liberi dopo che i bit originali sono stati spostati a sinistra o a destra.

Questo approccio è noto come *scorrimento logico*.

L'illustrazione seguente mostra i risultati di `11111111 << 1` (cioè `11111111` fatto scorrere a sinistra di `1` posizione), e di `11111111 >> 1` (cioè `11111111` fatto scorrere a destra di `1` posizione). I numeri verdi vengono spostati, i numeri grigi vengono scartati, e gli zeri rosa vengono inseriti:

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

Ecco come appare lo scorrimento di bit nel codice Swift:

```swift
let shiftBits: UInt8 = 4   // 00000100 in binario
shiftBits << 1             // 00001000
shiftBits << 2             // 00010000
shiftBits << 5             // 10000000
shiftBits << 6             // 00000000
shiftBits >> 2             // 00000001
```

Puoi usare lo scorrimento di bit per codificare e decodificare valori all'interno di altri tipi di dati:

```swift
let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16    // redComponent è 0xCC, ovvero 204
let greenComponent = (pink & 0x00FF00) >> 8   // greenComponent è 0x66, ovvero 102
let blueComponent = pink & 0x0000FF           // blueComponent è 0x99, ovvero 153
```

Questo esempio usa una costante `UInt32` chiamata `pink` per memorizzare un valore di colore dei Cascading Style Sheets per il colore rosa. Il valore di colore CSS `#CC6699` si scrive `0xCC6699` nella rappresentazione dei numeri esadecimali di Swift. Questo colore viene poi scomposto nelle sue componenti rossa (`CC`), verde (`66`) e blu (`99`) tramite l'operatore AND bit a bit (`&`) e l'operatore di scorrimento bit a bit a destra (`>>`).

La componente rossa si ottiene eseguendo un AND bit a bit tra i numeri `0xCC6699` e `0xFF0000`. Gli zeri di `0xFF0000` di fatto “mascherano” il secondo e il terzo byte di `0xCC6699`, facendo sì che `6699` venga ignorato e lasciando `0xCC0000` come risultato.

Questo numero viene poi fatto scorrere di 16 posizioni a destra (`>> 16`). Ogni coppia di caratteri di un numero esadecimale usa 8 bit, quindi uno spostamento di 16 posizioni a destra convertirà `0xCC0000` in `0x0000CC`. Questo è lo stesso di `0xCC`, che ha un valore decimale di `204`.

Analogamente, la componente verde si ottiene eseguendo un AND bit a bit tra i numeri `0xCC6699` e `0x00FF00`, il che dà un valore di output di `0x006600`. Questo valore di output viene poi fatto scorrere di otto posizioni a destra, dando un valore di `0x66`, che ha un valore decimale di `102`.

Infine, la componente blu si ottiene eseguendo un AND bit a bit tra i numeri `0xCC6699` e `0x0000FF`, il che dà un valore di output di `0x000099`. Poiché `0x000099` è già uguale a `0x99`, che ha un valore decimale di `153`, questo valore viene usato senza farlo scorrere a destra,

#### Comportamento dello scorrimento per gli interi con segno <a href="#comportamento-dello-scorrimento-per-gli-interi-con-segno" id="comportamento-dello-scorrimento-per-gli-interi-con-segno"></a>

Il comportamento dello scorrimento è più complesso per gli interi con segno che per quelli senza segno, a causa del modo in cui gli interi con segno sono rappresentati in binario. (Gli esempi seguenti si basano su interi con segno a 8 bit per semplicità, ma gli stessi principi si applicano agli interi con segno di qualsiasi dimensione.)

Gli interi con segno usano il loro primo bit (noto come *bit di segno*) per indicare se l'intero è positivo o negativo. Un bit di segno pari a `0` significa positivo, e un bit di segno pari a `1` significa negativo.

I bit rimanenti (noti come *bit di valore*) memorizzano il valore effettivo. I numeri positivi sono memorizzati esattamente nello stesso modo degli interi senza segno, contando in avanti a partire da `0`. Ecco come appaiono i bit all'interno di un `Int8` per il numero `4`:

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

Il bit di segno è `0` (che significa “positivo”), e i sette bit di valore sono semplicemente il numero `4`, scritto in notazione binaria.

I numeri negativi, invece, sono memorizzati in modo diverso. Vengono memorizzati sottraendo il loro valore assoluto da `2` elevato alla potenza di `n`, dove `n` è il numero di bit di valore. Un numero a otto bit ha sette bit di valore, quindi questo significa `2` elevato alla potenza di `7`, ovvero `128`.

Ecco come appaiono i bit all'interno di un `Int8` per il numero `-4`:

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

Questa volta, il bit di segno è `1` (che significa “negativo”), e i sette bit di valore hanno un valore binario di `124` (cioè `128 - 4`):

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

Questa codifica dei numeri negativi è nota come rappresentazione in *complemento a due*. Può sembrare un modo insolito di rappresentare i numeri negativi, ma presenta diversi vantaggi.

Innanzitutto, puoi sommare `-1` a `-4`, semplicemente eseguendo una normale addizione binaria di tutti e otto i bit (compreso il bit di segno), e scartando alla fine tutto ciò che non sta negli otto bit:

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

In secondo luogo, la rappresentazione in complemento a due ti permette anche di far scorrere i bit dei numeri negativi a sinistra e a destra come per i numeri positivi, ottenendo comunque il raddoppio per ogni scorrimento a sinistra, o il dimezzamento per ogni scorrimento a destra. Per ottenere questo, si usa una regola aggiuntiva quando gli interi con segno vengono fatti scorrere a destra: quando fai scorrere a destra gli interi con segno, applica le stesse regole degli interi senza segno, ma riempi gli eventuali bit vuoti a sinistra con il *bit di segno*, anziché con uno zero.

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

Questa azione garantisce che gli interi con segno mantengano lo stesso segno dopo essere stati fatti scorrere a destra, ed è nota come *scorrimento aritmetico*.

A causa del modo particolare in cui sono memorizzati i numeri positivi e negativi, farli scorrere a destra li avvicina a zero. Mantenere invariato il bit di segno durante questo scorrimento fa sì che gli interi negativi restino negativi mentre il loro valore si avvicina a zero.

## Operatori di overflow <a href="#operatori-di-overflow" id="operatori-di-overflow"></a>

Se provi a inserire in una costante o variabile intera un numero che non può contenere, per impostazione predefinita Swift segnala un errore anziché consentire la creazione di un valore non valido. Questo comportamento offre una sicurezza aggiuntiva quando lavori con numeri troppo grandi o troppo piccoli.

Per esempio, il tipo intero `Int16` può contenere qualsiasi intero con segno tra `-32768` e `32767`. Tentare di impostare una costante o una variabile `Int16` a un numero al di fuori di questo intervallo causa un errore:

```swift
var potentialOverflow = Int16.max
// potentialOverflow è uguale a 32767, che è il valore massimo che un Int16 può contenere
potentialOverflow += 1
// questo causa un errore
```

Fornire una gestione degli errori quando i valori diventano troppo grandi o troppo piccoli ti dà molta più flessibilità quando scrivi codice per le condizioni ai valori limite.

Tuttavia, quando vuoi specificamente che una condizione di overflow tronchi il numero di bit disponibili, puoi abilitare questo comportamento anziché attivare un errore. Swift fornisce tre *operatori di overflow* aritmetici che abilitano il comportamento di overflow per i calcoli con gli interi. Questi operatori iniziano tutti con una e commerciale (`&`):

* Addizione con overflow (`&+`)
* Sottrazione con overflow (`&-`)
* Moltiplicazione con overflow (`&*`)

### Overflow dei valori <a href="#overflow-dei-valori" id="overflow-dei-valori"></a>

I numeri possono andare in overflow sia in direzione positiva sia in direzione negativa.

Ecco un esempio di ciò che accade quando a un intero senza segno è consentito andare in overflow in direzione positiva, usando l'operatore di addizione con overflow (`&+`):

```swift
var unsignedOverflow = UInt8.max
// unsignedOverflow è uguale a 255, che è il valore massimo che un UInt8 può contenere
unsignedOverflow = unsignedOverflow &+ 1
// unsignedOverflow ora è uguale a 0
```

La variabile `unsignedOverflow` viene inizializzata con il valore massimo che un `UInt8` può contenere (`255`, ovvero `11111111` in binario). Viene poi incrementata di `1` usando l'operatore di addizione con overflow (`&+`). Questo spinge la sua rappresentazione binaria appena oltre la dimensione che un `UInt8` può contenere, facendola andare in overflow oltre i suoi limiti, come mostrato nel diagramma seguente. Il valore che rimane entro i limiti del `UInt8` dopo l'addizione con overflow è `00000000`, ovvero zero.

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

Qualcosa di simile accade quando a un intero senza segno è consentito andare in overflow in direzione negativa. Ecco un esempio che usa l'operatore di sottrazione con overflow (`&-`):

```swift
var unsignedOverflow = UInt8.min
// unsignedOverflow è uguale a 0, che è il valore minimo che un UInt8 può contenere
unsignedOverflow = unsignedOverflow &- 1
// unsignedOverflow ora è uguale a 255
```

Il valore minimo che un `UInt8` può contenere è zero, ovvero `00000000` in binario. Se sottrai `1` da `00000000` usando l'operatore di sottrazione con overflow (`&-`), il numero andrà in overflow e ricomincerà da `11111111`, ovvero `255` in decimale.

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

L'overflow si verifica anche per gli interi con segno. Tutte le addizioni e sottrazioni per gli interi con segno vengono eseguite bit a bit, con il bit di segno incluso come parte dei numeri sommati o sottratti, come descritto in [Operatori di scorrimento bit a bit a sinistra e a destra](/guida-al-linguaggio/operatori-avanzati.md#operatori-di-scorrimento-bit-a-bit-a-sinistra-e-a-destra).

```swift
var signedOverflow = Int8.min
// signedOverflow è uguale a -128, che è il valore minimo che un Int8 può contenere
signedOverflow = signedOverflow &- 1
// signedOverflow ora è uguale a 127
```

Il valore minimo che un `Int8` può contenere è `-128`, ovvero `10000000` in binario. Sottrarre `1` da questo numero binario con l'operatore di overflow dà un valore binario di `01111111`, che inverte il bit di segno e dà il valore positivo `127`, il valore positivo massimo che un `Int8` può contenere.

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

Sia per gli interi con segno sia per quelli senza segno, l'overflow in direzione positiva ricomincia dal valore intero valido massimo al minimo, e l'overflow in direzione negativa ricomincia dal valore minimo al massimo.

## Precedenza e associatività <a href="#precedenza-e-associativita" id="precedenza-e-associativita"></a>

La *precedenza* degli operatori dà ad alcuni operatori una priorità più alta rispetto ad altri; questi operatori vengono applicati per primi.

L'*associatività* degli operatori definisce come vengono raggruppati gli operatori con la stessa precedenza — raggruppati da sinistra, oppure raggruppati da destra. Pensala come se significasse “si associano con l'espressione alla loro sinistra” oppure “si associano con l'espressione alla loro destra”.

È importante considerare la precedenza e l'associatività di ciascun operatore quando si determina l'ordine in cui verrà calcolata un'espressione composta. Per esempio, la precedenza degli operatori spiega perché l'espressione seguente è uguale a `17`.

```swift
2 + 3 % 4 * 5
// questo è uguale a 17
```

Se leggessi rigorosamente da sinistra a destra, potresti aspettarti che l'espressione venga calcolata come segue:

* `2` più `3` è uguale a `5`
* `5` resto `4` è uguale a `1`
* `1` per `5` è uguale a `5`

Tuttavia, la risposta effettiva è `17`, non `5`. Gli operatori con precedenza più alta vengono valutati prima di quelli con precedenza più bassa. In Swift, come in C, l'operatore di resto (`%`) e l'operatore di moltiplicazione (`*`) hanno una precedenza più alta dell'operatore di addizione (`+`). Di conseguenza, vengono entrambi valutati prima che venga presa in considerazione l'addizione.

Tuttavia, resto e moltiplicazione hanno la *stessa* precedenza tra loro. Per determinare l'esatto ordine di valutazione da usare, devi considerare anche la loro associatività. Resto e moltiplicazione si associano entrambi con l'espressione alla loro sinistra. Pensalo come l'aggiunta di parentesi implicite attorno a queste parti dell'espressione, a partire dalla loro sinistra:

```swift
2 + ((3 % 4) * 5)
```

`(3 % 4)` vale `3`, quindi questo equivale a:

```swift
2 + (3 * 5)
```

`(3 * 5)` vale `15`, quindi questo equivale a:

```swift
2 + 15
```

Questo calcolo produce la risposta finale di `17`.

Per informazioni sugli operatori forniti dalla libreria standard di Swift, compreso un elenco completo dei gruppi di precedenza degli operatori e delle impostazioni di associatività, vedi [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations).

{% hint style="info" %}
**Nota:** Le regole di precedenza e di associatività degli operatori di Swift sono più semplici e più prevedibili di quelle presenti in C e Objective-C. Tuttavia, ciò significa che non sono esattamente le stesse dei linguaggi derivati dal C. Fai attenzione ad assicurarti che le interazioni tra operatori si comportino ancora nel modo che intendi quando porti codice esistente in Swift.
{% endhint %}

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

Classi e strutture possono fornire le proprie implementazioni di operatori esistenti. Questo è noto come *overload* degli operatori esistenti.

L'esempio seguente mostra come implementare l'operatore di addizione aritmetica (`+`) per una struttura personalizzata. L'operatore di addizione aritmetica è un operatore binario perché opera su due operandi ed è un operatore infisso perché compare tra quei due operandi.

L'esempio definisce una struttura `Vector2D` per un vettore di posizione bidimensionale `(x, y)`, seguita dalla definizione di un *metodo operatore* per sommare istanze della struttura `Vector2D`:

```swift
struct Vector2D {
    var x = 0.0, y = 0.0
}

extension Vector2D {
    static func + (left: Vector2D, right: Vector2D) -> Vector2D {
       return Vector2D(x: left.x + right.x, y: left.y + right.y)
    }
}
```

Il metodo operatore è definito come metodo di tipo su `Vector2D`, con un nome di metodo che corrisponde all'operatore di cui eseguire l'overload (`+`). Poiché l'addizione non fa parte del comportamento essenziale di un vettore, il metodo di tipo è definito in un'estensione di `Vector2D` anziché nella dichiarazione principale della struttura `Vector2D`. Poiché l'operatore di addizione aritmetica è un operatore binario, questo metodo operatore accetta due parametri di input di tipo `Vector2D` e restituisce un unico valore di output, anch'esso di tipo `Vector2D`.

In questa implementazione, i parametri di input si chiamano `left` e `right` per rappresentare le istanze di `Vector2D` che si troveranno sul lato sinistro e sul lato destro dell'operatore `+`. Il metodo restituisce una nuova istanza di `Vector2D`, le cui proprietà `x` e `y` sono inizializzate con la somma delle proprietà `x` e `y` delle due istanze di `Vector2D` che vengono sommate.

Il metodo di tipo può essere usato come operatore infisso tra istanze esistenti di `Vector2D`:

```swift
let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// combinedVector è un'istanza di Vector2D con valori (5.0, 5.0)
```

Questo esempio somma i vettori `(3.0, 1.0)` e `(2.0, 4.0)` per ottenere il vettore `(5.0, 5.0)`, come illustrato di seguito.

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

### Operatori prefissi e postfissi <a href="#operatori-prefissi-e-postfissi" id="operatori-prefissi-e-postfissi"></a>

L'esempio mostrato sopra dimostra un'implementazione personalizzata di un operatore binario infisso. Classi e strutture possono anche fornire implementazioni degli *operatori unari* standard. Gli operatori unari operano su un singolo operando. Sono *prefissi* se precedono il loro operando (come `-a`) e operatori *postfissi* se seguono il loro operando (come `b!`).

Implementi un operatore unario prefisso o postfisso scrivendo il modificatore `prefix` o `postfix` prima della parola chiave `func` quando dichiari il metodo operatore:

```swift
extension Vector2D {
    static prefix func - (vector: Vector2D) -> Vector2D {
        return Vector2D(x: -vector.x, y: -vector.y)
    }
}
```

L'esempio qui sopra implementa l'operatore meno unario (`-a`) per le istanze di `Vector2D`. L'operatore meno unario è un operatore prefisso, e quindi questo metodo deve essere qualificato con il modificatore `prefix`.

Per i semplici valori numerici, l'operatore meno unario converte i numeri positivi nel loro equivalente negativo e viceversa. L'implementazione corrispondente per le istanze di `Vector2D` esegue questa operazione su entrambe le proprietà `x` e `y`:

```swift
let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
// negative è un'istanza di Vector2D con valori (-3.0, -4.0)
let alsoPositive = -negative
// alsoPositive è un'istanza di Vector2D con valori (3.0, 4.0)
```

### Operatori di assegnamento composti <a href="#operatori-di-assegnamento-composti" id="operatori-di-assegnamento-composti"></a>

Gli *operatori di assegnamento composti* combinano l'assegnamento (`=`) con un'altra operazione. Per esempio, l'operatore di assegnamento con addizione (`+=`) combina addizione e assegnamento in un'unica operazione. Contrassegni il tipo del parametro di input sinistro di un operatore di assegnamento composto come `inout`, perché il valore del parametro verrà modificato direttamente dall'interno del metodo operatore.

L'esempio seguente implementa un metodo operatore di assegnamento con addizione per le istanze di `Vector2D`:

```swift
extension Vector2D {
    static func += (left: inout Vector2D, right: Vector2D) {
        left = left + right
    }
}
```

Poiché un operatore di addizione è stato definito in precedenza, non hai bisogno di reimplementare qui il processo di addizione. Invece, il metodo operatore di assegnamento con addizione si avvale del metodo operatore di addizione esistente, e lo usa per impostare il valore sinistro al valore sinistro più il valore destro:

```swift
var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd
// original ora ha valori (4.0, 6.0)
```

{% hint style="info" %}
**Nota:** Non è possibile eseguire l'overload dell'operatore di assegnamento predefinito (`=`). Solo gli operatori di assegnamento composti possono essere sottoposti a overload. Analogamente, l'operatore condizionale ternario (`a ? b : c`) non può essere sottoposto a overload.
{% endhint %}

### Operatori di equivalenza <a href="#operatori-di-equivalenza" id="operatori-di-equivalenza"></a>

Per impostazione predefinita, le classi e le strutture personalizzate non hanno un'implementazione degli *operatori di equivalenza*, noti come operatore *uguale a* (`==`) e operatore *diverso da* (`!=`). Di solito implementi l'operatore `==`, e usi l'implementazione predefinita dell'operatore `!=` della libreria standard di Swift che nega il risultato dell'operatore `==`. Ci sono due modi per implementare l'operatore `==`: puoi implementarlo tu stesso, oppure, per molti tipi, puoi chiedere a Swift di sintetizzare un'implementazione per te. In entrambi i casi, aggiungi la conformità al protocollo `Equatable` della libreria standard di Swift.

Fornisci un'implementazione dell'operatore `==` nello stesso modo in cui implementi gli altri operatori infissi:

```swift
extension Vector2D: Equatable {
    static func == (left: Vector2D, right: Vector2D) -> Bool {
       return (left.x == right.x) && (left.y == right.y)
    }
}
```

L'esempio qui sopra implementa un operatore `==` per verificare se due istanze di `Vector2D` hanno valori equivalenti. Nel contesto di `Vector2D`, ha senso considerare “uguale” con il significato di “entrambe le istanze hanno gli stessi valori `x` e `y`”, e quindi questa è la logica usata dall'implementazione dell'operatore.

Ora puoi usare questo operatore per verificare se due istanze di `Vector2D` sono equivalenti:

```swift
let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
    print("These two vectors are equivalent.")
}
// Stampa "These two vectors are equivalent."
```

In molti casi semplici, puoi chiedere a Swift di fornirti implementazioni sintetizzate degli operatori di equivalenza, come descritto in [Adottare un protocollo usando un'implementazione sintetizzata](/guida-al-linguaggio/protocolli.md#adottare-un-protocollo-usando-unimplementazione-sintetizzata).

## Operatori personalizzati <a href="#operatori-personalizzati" id="operatori-personalizzati"></a>

Puoi dichiarare e implementare i tuoi *operatori personalizzati* oltre agli operatori standard forniti da Swift. Per un elenco dei caratteri che possono essere usati per definire operatori personalizzati, vedi [Operatori](/riferimento-del-linguaggio/struttura-lessicale.md#operatori).

I nuovi operatori vengono dichiarati a livello globale usando la parola chiave `operator`, e sono contrassegnati con i modificatori `prefix`, `infix` o `postfix`:

```swift
prefix operator +++
```

L'esempio qui sopra definisce un nuovo operatore prefisso chiamato `+++`. Questo operatore non ha un significato preesistente in Swift, e quindi più avanti gli viene dato un significato personalizzato nel contesto specifico del lavoro con le istanze di `Vector2D`. Ai fini di questo esempio, `+++` viene trattato come un nuovo operatore di “raddoppio prefisso”. Raddoppia i valori `x` e `y` di un'istanza di `Vector2D`, sommando il vettore a sé stesso con l'operatore di assegnamento con addizione definito in precedenza. Per implementare l'operatore `+++`, aggiungi a `Vector2D` un metodo di tipo chiamato `+++` come segue:

```swift
extension Vector2D {
    static prefix func +++ (vector: inout Vector2D) -> Vector2D {
        vector += vector
        return vector
    }
}

var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
let afterDoubling = +++toBeDoubled
// toBeDoubled ora ha valori (2.0, 8.0)
// anche afterDoubling ha valori (2.0, 8.0)
```

### Precedenza per gli operatori infissi personalizzati <a href="#precedenza-per-gli-operatori-infissi-personalizzati" id="precedenza-per-gli-operatori-infissi-personalizzati"></a>

Gli operatori infissi personalizzati appartengono ciascuno a un gruppo di precedenza. Un gruppo di precedenza specifica la precedenza di un operatore rispetto agli altri operatori infissi, oltre all'associatività dell'operatore. Vedi [Precedenza e associatività](/guida-al-linguaggio/operatori-avanzati.md#precedenza-e-associativita) per una spiegazione di come queste caratteristiche influiscono sull'interazione di un operatore infisso con altri operatori infissi.

A un operatore infisso personalizzato che non è collocato esplicitamente in un gruppo di precedenza viene assegnato un gruppo di precedenza predefinito con una precedenza immediatamente superiore alla precedenza dell'operatore condizionale ternario.

L'esempio seguente definisce un nuovo operatore infisso personalizzato chiamato `+-`, che appartiene al gruppo di precedenza `AdditionPrecedence`:

```swift
infix operator +-: AdditionPrecedence
extension Vector2D {
    static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y - right.y)
    }
}
let firstVector = Vector2D(x: 1.0, y: 2.0)
let secondVector = Vector2D(x: 3.0, y: 4.0)
let plusMinusVector = firstVector +- secondVector
// plusMinusVector è un'istanza di Vector2D con valori (4.0, -2.0)
```

Questo operatore somma i valori `x` di due vettori, e sottrae il valore `y` del secondo vettore da quello del primo. Poiché è in sostanza un operatore “additivo”, gli è stato assegnato lo stesso gruppo di precedenza degli operatori infissi additivi come `+` e `-`. Per informazioni sugli operatori forniti dalla libreria standard di Swift, compreso un elenco completo dei gruppi di precedenza degli operatori e delle impostazioni di associatività, vedi [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). Per maggiori informazioni sui gruppi di precedenza e per vedere la sintassi per definire i tuoi operatori e gruppi di precedenza, vedi [Dichiarazione di operatore](/riferimento-del-linguaggio/dichiarazioni.md#dichiarazione-di-operatore).

{% hint style="info" %}
**Nota:** Non specifichi una precedenza quando definisci un operatore prefisso o postfisso. Tuttavia, se applichi sia un operatore prefisso sia un operatore postfisso allo stesso operando, viene applicato per primo l'operatore postfisso.
{% endhint %}

## Result builder <a href="#result-builder" id="result-builder"></a>

Un *result builder* è un tipo che definisci che aggiunge una sintassi per creare dati annidati, come un elenco o un albero, in modo naturale e dichiarativo. Il codice che usa il result builder può includere la normale sintassi di Swift, come `if` e `for`, per gestire porzioni di dati condizionali o ripetute.

Il codice seguente definisce alcuni tipi per disegnare su una singola riga usando stelle e testo.

```swift
protocol Drawable {
    func draw() -> String
}
struct Line: Drawable {
    var elements: [Drawable]
    func draw() -> String {
        return elements.map { $0.draw() }.joined(separator: "")
    }
}
struct Text: Drawable {
    var content: String
    init(_ content: String) { self.content = content }
    func draw() -> String { return content }
}
struct Space: Drawable {
    func draw() -> String { return " " }
}
struct Stars: Drawable {
    var length: Int
    func draw() -> String { return String(repeating: "*", count: length) }
}
struct AllCaps: Drawable {
    var content: Drawable
    func draw() -> String { return content.draw().uppercased() }
}
```

Il protocollo `Drawable` definisce il requisito per qualcosa che può essere disegnato, come una linea o una forma: il tipo deve implementare un metodo `draw()`. La struttura `Line` rappresenta un disegno su una singola riga, e funge da contenitore di livello superiore per la maggior parte dei disegni. Per disegnare una `Line`, la struttura chiama `draw()` su ciascuno dei componenti della riga, e poi concatena le stringhe risultanti in un'unica stringa. La struttura `Text` racchiude una stringa per renderla parte di un disegno. La struttura `AllCaps` racchiude e modifica un altro disegno, convertendo in maiuscolo qualsiasi testo presente nel disegno.

È possibile creare un disegno con questi tipi chiamando i loro inizializzatori:

```swift
let name: String? = "Ravi Patel"
let manualDrawing = Line(elements: [
     Stars(length: 3),
     Text("Hello"),
     Space(),
     AllCaps(content: Text((name ?? "World") + "!")),
     Stars(length: 2),
])
print(manualDrawing.draw())
// Stampa "***Hello RAVI PATEL!**".
```

Questo codice funziona, ma è un po' goffo. Le parentesi profondamente annidate dopo `AllCaps` sono difficili da leggere. La logica di ripiego per usare "World" quando `name` è `nil` deve essere scritta inline usando l'operatore `??`, cosa che sarebbe difficile con qualunque cosa più complessa. Se avessi bisogno di includere degli switch o dei cicli `for` per costruire parte del disegno, non ci sarebbe modo di farlo. Un result builder ti permette di riscrivere codice come questo in modo che appaia come normale codice Swift.

Per definire un result builder, scrivi l'attributo `@resultBuilder` sulla dichiarazione di un tipo. Per esempio, questo codice definisce un result builder chiamato `DrawingBuilder`, che ti permette di usare una sintassi dichiarativa per descrivere un disegno:

```swift
@resultBuilder
struct DrawingBuilder {
    static func buildBlock(_ components: Drawable...) -> Drawable {
        return Line(elements: components)
    }
    static func buildEither(first: Drawable) -> Drawable {
        return first
    }
    static func buildEither(second: Drawable) -> Drawable {
        return second
    }
}
```

La struttura `DrawingBuilder` definisce tre metodi che implementano parti della sintassi del result builder. Il metodo `buildBlock(_:)` aggiunge il supporto per la scrittura di una serie di righe in un blocco di codice. Combina i componenti di quel blocco in una `Line`. I metodi `buildEither(first:)` e `buildEither(second:)` aggiungono il supporto per `if`-`else`.

Puoi applicare l'attributo `@DrawingBuilder` al parametro di una funzione, il che trasforma una closure passata alla funzione nel valore che il result builder crea a partire da quella closure. Per esempio:

```swift
func draw(@DrawingBuilder content: () -> Drawable) -> Drawable {
    return content()
}
func caps(@DrawingBuilder content: () -> Drawable) -> Drawable {
    return AllCaps(content: content())
}

func makeGreeting(for name: String? = nil) -> Drawable {
    let greeting = draw {
        Stars(length: 3)
        Text("Hello")
        Space()
        caps {
            if let name = name {
                Text(name + "!")
            } else {
                Text("World!")
            }
        }
        Stars(length: 2)
    }
    return greeting
}
let genericGreeting = makeGreeting()
print(genericGreeting.draw())
// Stampa "***Hello WORLD!**".

let personalGreeting = makeGreeting(for: "Ravi Patel")
print(personalGreeting.draw())
// Stampa "***Hello RAVI PATEL!**".
```

La funzione `makeGreeting(for:)` accetta un parametro `name` e lo usa per disegnare un saluto personalizzato. Le funzioni `draw(_:)` e `caps(_:)` accettano entrambe una singola closure come argomento, contrassegnata con l'attributo `@DrawingBuilder`. Quando chiami quelle funzioni, usi la sintassi speciale definita da `DrawingBuilder`. Swift trasforma quella descrizione dichiarativa di un disegno in una serie di chiamate ai metodi di `DrawingBuilder` per costruire il valore che viene passato come argomento della funzione. Per esempio, Swift trasforma la chiamata a `caps(_:)` in quell'esempio in codice simile al seguente:

```swift
let capsDrawing = caps {
    let partialDrawing: Drawable
    if let name = name {
        let text = Text(name + "!")
        partialDrawing = DrawingBuilder.buildEither(first: text)
    } else {
        let text = Text("World!")
        partialDrawing = DrawingBuilder.buildEither(second: text)
    }
    return partialDrawing
}
```

Swift trasforma il blocco `if`-`else` in chiamate ai metodi `buildEither(first:)` e `buildEither(second:)`. Anche se non chiami questi metodi nel tuo codice, mostrare il risultato della trasformazione rende più facile vedere come Swift trasforma il tuo codice quando usi la sintassi di `DrawingBuilder`.

Per aggiungere il supporto alla scrittura di cicli `for` nella speciale sintassi di disegno, aggiungi un metodo `buildArray(_:)`.

```swift
extension DrawingBuilder {
    static func buildArray(_ components: [Drawable]) -> Drawable {
        return Line(elements: components)
    }
}
let manyStars = draw {
    Text("Stars:")
    for length in 1...3 {
        Space()
        Stars(length: length)
    }
}
```

Nel codice qui sopra, il ciclo `for` crea un array di disegni, e il metodo `buildArray(_:)` trasforma quell'array in una `Line`.

Per un elenco completo di come Swift trasforma la sintassi dei builder in chiamate ai metodi del tipo builder, vedi [resultBuilder](/riferimento-del-linguaggio/attributi.md#resultbuilder).
