> 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/strutture-e-classi.md).

# Strutture e classi (Structures and Classes)

Modella tipi personalizzati che incapsulano dati.

Le *strutture* e le *classi* sono costrutti flessibili e di uso generale che diventano i mattoni fondamentali del codice del tuo programma. Definisci proprietà e metodi per aggiungere funzionalità alle tue strutture e classi usando la stessa sintassi che usi per definire costanti, variabili e funzioni.

A differenza di altri linguaggi di programmazione, Swift non richiede di creare file separati di interfaccia e di implementazione per le strutture e le classi personalizzate. In Swift, definisci una struttura o una classe in un unico file, e l'interfaccia esterna di quella classe o struttura viene resa automaticamente disponibile all'uso da parte di altro codice.

{% hint style="info" %}
**Nota:** Un'istanza di una classe è tradizionalmente nota come *oggetto*. Tuttavia, in Swift strutture e classi sono molto più vicine per funzionalità che in altri linguaggi, e gran parte di questo capitolo descrive funzionalità che si applicano alle istanze di un tipo classe *o* di un tipo struttura. Per questo motivo, viene usato il termine più generale *istanza*.
{% endhint %}

## Confrontare strutture e classi <a href="#confrontare-strutture-e-classi" id="confrontare-strutture-e-classi"></a>

In Swift strutture e classi hanno molte cose in comune. Entrambe possono:

* Definire proprietà per memorizzare valori
* Definire metodi per fornire funzionalità
* Definire subscript per fornire accesso ai loro valori usando la sintassi dei subscript
* Definire inizializzatori per impostare il loro stato iniziale
* Essere estese per espandere la loro funzionalità oltre un'implementazione predefinita
* Essere conformi a protocolli per fornire funzionalità standard di un certo tipo

Per maggiori informazioni, vedi [Proprietà](/guida-al-linguaggio/proprieta.md), [Metodi](/guida-al-linguaggio/metodi.md), [Subscript](/guida-al-linguaggio/subscript.md), [Inizializzazione](/guida-al-linguaggio/inizializzazione.md), [Estensioni](/guida-al-linguaggio/estensioni.md) e [Protocolli](/guida-al-linguaggio/protocolli.md).

Le classi hanno capacità aggiuntive che le strutture non hanno:

* L'ereditarietà permette a una classe di ereditare le caratteristiche di un'altra.
* Il type casting ti permette di verificare e interpretare il tipo di un'istanza di classe in fase di esecuzione.
* I deinizializzatori permettono a un'istanza di una classe di liberare le risorse che ha allocato.
* Il conteggio dei riferimenti consente più di un riferimento a un'istanza di classe.

Per maggiori informazioni, vedi [Ereditarietà](/guida-al-linguaggio/ereditarieta.md), [Type casting](/guida-al-linguaggio/type-casting.md), [Deinizializzazione](/guida-al-linguaggio/deinizializzazione.md) e [Conteggio automatico dei riferimenti](/guida-al-linguaggio/conteggio-automatico-dei-riferimenti.md).

Le capacità aggiuntive supportate dalle classi hanno come costo una maggiore complessità. Come linea guida generale, preferisci le strutture perché sono più facili da comprendere, e usa le classi quando sono appropriate o necessarie. In pratica, ciò significa che la maggior parte dei tipi personalizzati che definisci saranno strutture ed enumerazioni. Per un confronto più dettagliato, vedi [Choosing Between Structures and Classes](https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes).

{% hint style="info" %}
**Nota:** Classi e actor condividono molte delle stesse caratteristiche e degli stessi comportamenti. Per informazioni sugli actor, vedi [Concorrenza](/guida-al-linguaggio/concorrenza.md).
{% endhint %}

### Sintassi di definizione <a href="#sintassi-di-definizione" id="sintassi-di-definizione"></a>

Strutture e classi hanno una sintassi di definizione simile. Introduci le strutture con la parola chiave `struct` e le classi con la parola chiave `class`. Entrambe collocano la loro intera definizione all'interno di una coppia di parentesi graffe:

```swift
struct SomeStructure {
    // qui va la definizione della struttura
}
class SomeClass {
    // qui va la definizione della classe
}
```

{% hint style="info" %}
**Nota:** Ogni volta che definisci una nuova struttura o classe, definisci un nuovo tipo Swift. Assegna ai tipi nomi in `UpperCamelCase` (come `SomeStructure` e `SomeClass` qui) per corrispondere all'uso delle maiuscole dei tipi standard di Swift (come `String`, `Int` e `Bool`). Assegna a proprietà e metodi nomi in `lowerCamelCase` (come `frameRate` e `incrementCount`) per distinguerli dai nomi dei tipi.
{% endhint %}

Ecco un esempio di definizione di una struttura e di definizione di una classe:

```swift
struct Resolution {
    var width = 0
    var height = 0
}
class VideoMode {
    var resolution = Resolution()
    var interlaced = false
    var frameRate = 0.0
    var name: String?
}
```

L'esempio qui sopra definisce una nuova struttura chiamata `Resolution`, per descrivere una risoluzione dello schermo basata sui pixel. Questa struttura ha due proprietà memorizzate chiamate `width` e `height`. Le proprietà memorizzate sono costanti o variabili raggruppate e memorizzate come parte della struttura o della classe. Il tipo di queste due proprietà viene inferito come `Int` impostandole a un valore intero iniziale di `0`.

L'esempio qui sopra definisce anche una nuova classe chiamata `VideoMode`, per descrivere una specifica modalità video per la visualizzazione video. Questa classe ha quattro proprietà memorizzate variabili. La prima, `resolution`, è inizializzata con una nuova istanza della struttura `Resolution`, da cui viene inferito un tipo di proprietà `Resolution`. Per le altre tre proprietà, le nuove istanze di `VideoMode` verranno inizializzate con un'impostazione `interlaced` pari a `false` (che significa “video non interlacciato”), una frequenza di fotogrammi di riproduzione di `0.0`, e un valore `String` opzionale chiamato `name`. Alla proprietà `name` viene assegnato automaticamente un valore predefinito di `nil`, ovvero “nessun valore `name`”, perché è di un tipo opzionale.

### Istanze di strutture e di classi <a href="#istanze-di-strutture-e-di-classi" id="istanze-di-strutture-e-di-classi"></a>

La definizione della struttura `Resolution` e la definizione della classe `VideoMode` descrivono soltanto come sarà fatta una `Resolution` o una `VideoMode`. Di per sé non descrivono una specifica risoluzione o modalità video. Per farlo, devi creare un'istanza della struttura o della classe.

La sintassi per creare istanze è molto simile sia per le strutture sia per le classi:

```swift
let someResolution = Resolution()
let someVideoMode = VideoMode()
```

Strutture e classi usano entrambe la sintassi di inizializzazione per le nuove istanze. La forma più semplice della sintassi di inizializzazione usa il nome del tipo della classe o della struttura seguito da parentesi vuote, come `Resolution()` o `VideoMode()`. Questo crea una nuova istanza della classe o della struttura, con tutte le proprietà inizializzate ai loro valori predefiniti. L'inizializzazione di classi e strutture è descritta in modo più dettagliato in [Inizializzazione](/guida-al-linguaggio/inizializzazione.md).

### Accedere alle proprietà <a href="#accedere-alle-proprieta" id="accedere-alle-proprieta"></a>

Puoi accedere alle proprietà di un'istanza usando la *sintassi a punto*. Nella sintassi a punto, scrivi il nome della proprietà subito dopo il nome dell'istanza, separati da un punto (`.`), senza spazi:

```swift
print("The width of someResolution is \(someResolution.width)")
// Stampa "The width of someResolution is 0".
```

In questo esempio, `someResolution.width` si riferisce alla proprietà `width` di `someResolution`, e restituisce il suo valore iniziale predefinito di `0`.

Puoi scendere nelle sotto-proprietà, come la proprietà `width` nella proprietà `resolution` di una `VideoMode`:

```swift
print("The width of someVideoMode is \(someVideoMode.resolution.width)")
// Stampa "The width of someVideoMode is 0".
```

Puoi anche usare la sintassi a punto per assegnare un nuovo valore a una proprietà variabile:

```swift
someVideoMode.resolution.width = 1280
print("The width of someVideoMode is now \(someVideoMode.resolution.width)")
// Stampa "The width of someVideoMode is now 1280".
```

### Inizializzatori memberwise per i tipi struttura <a href="#inizializzatori-memberwise-per-i-tipi-struttura" id="inizializzatori-memberwise-per-i-tipi-struttura"></a>

Tutte le strutture hanno un *inizializzatore memberwise* generato automaticamente, che puoi usare per inizializzare le proprietà membro delle nuove istanze della struttura. I valori iniziali per le proprietà della nuova istanza possono essere passati per nome all'inizializzatore memberwise:

```swift
let vga = Resolution(width: 640, height: 480)
```

A differenza delle strutture, le istanze di classe non ricevono un inizializzatore memberwise predefinito. Gli inizializzatori sono descritti in modo più dettagliato in [Inizializzazione](/guida-al-linguaggio/inizializzazione.md).

## Strutture ed enumerazioni sono tipi valore <a href="#strutture-ed-enumerazioni-sono-tipi-valore" id="strutture-ed-enumerazioni-sono-tipi-valore"></a>

Un *tipo valore* è un tipo il cui valore viene *copiato* quando viene assegnato a una variabile o a una costante, o quando viene passato a una funzione.

In realtà hai già usato ampiamente i tipi valore nei capitoli precedenti. Di fatto, tutti i tipi di base in Swift — interi, numeri in virgola mobile, booleani, stringhe, array e dizionari — sono tipi valore, e sono implementati dietro le quinte come strutture.

In Swift tutte le strutture e le enumerazioni sono tipi valore. Ciò significa che qualsiasi istanza di struttura e di enumerazione che crei — e qualsiasi tipo valore che abbiano come proprietà — viene sempre copiata quando viene passata da una parte all'altra nel tuo codice.

{% hint style="info" %}
**Nota:** Le collezioni definite dalla libreria standard di Swift, come array, dizionari e stringhe, usano un'ottimizzazione per ridurre il costo in prestazioni della copia. Invece di creare immediatamente una copia, queste collezioni condividono la memoria in cui sono memorizzati gli elementi tra l'istanza originale e tutte le copie. Se una delle copie della collezione viene modificata, gli elementi vengono copiati subito prima della modifica. Il comportamento che vedi nel tuo codice è sempre come se la copia fosse avvenuta immediatamente.
{% endhint %}

Considera questo esempio, che usa la struttura `Resolution` dell'esempio precedente:

```swift
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
```

Questo esempio dichiara una costante chiamata `hd` e la imposta a un'istanza di `Resolution` inizializzata con la larghezza e l'altezza del video full HD (1920 pixel di larghezza per 1080 pixel di altezza).

Poi dichiara una variabile chiamata `cinema` e la imposta al valore corrente di `hd`. Poiché `Resolution` è una struttura, viene creata una *copia* dell'istanza esistente, e questa nuova copia viene assegnata a `cinema`. Anche se `hd` e `cinema` ora hanno la stessa larghezza e la stessa altezza, dietro le quinte sono due istanze completamente diverse.

Successivamente, la proprietà `width` di `cinema` viene modificata per corrispondere alla larghezza del formato 2K, leggermente più ampio, usato per la proiezione cinematografica digitale (2048 pixel di larghezza e 1080 pixel di altezza):

```swift
cinema.width = 2048
```

Controllando la proprietà `width` di `cinema` si vede che è effettivamente cambiata in `2048`:

```swift
print("cinema is now \(cinema.width) pixels wide")
// Stampa "cinema is now 2048 pixels wide".
```

Tuttavia, la proprietà `width` dell'istanza originale `hd` ha ancora il vecchio valore di `1920`:

```swift
print("hd is still \(hd.width) pixels wide")
// Stampa "hd is still 1920 pixels wide".
```

Quando a `cinema` è stato dato il valore corrente di `hd`, i *valori* memorizzati in `hd` sono stati copiati nella nuova istanza `cinema`. Il risultato finale sono state due istanze completamente separate che contenevano gli stessi valori numerici. Tuttavia, poiché sono istanze separate, impostare la larghezza di `cinema` a `2048` non influisce sulla larghezza memorizzata in `hd`, come mostrato nella figura seguente:

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

Lo stesso comportamento si applica alle enumerazioni:

```swift
enum CompassPoint {
    case north, south, east, west
    mutating func turnNorth() {
        self = .north
    }
}
var currentDirection = CompassPoint.west
let rememberedDirection = currentDirection
currentDirection.turnNorth()

print("The current direction is \(currentDirection)")
print("The remembered direction is \(rememberedDirection)")
// Stampa "The current direction is north".
// Stampa "The remembered direction is west".
```

Quando a `rememberedDirection` viene assegnato il valore di `currentDirection`, in realtà viene impostata a una copia di quel valore. Cambiare in seguito il valore di `currentDirection` non influisce sulla copia del valore originale memorizzata in `rememberedDirection`.

## Le classi sono tipi riferimento <a href="#le-classi-sono-tipi-riferimento" id="le-classi-sono-tipi-riferimento"></a>

A differenza dei tipi valore, i *tipi riferimento* *non* vengono copiati quando vengono assegnati a una variabile o a una costante, o quando vengono passati a una funzione. Invece di una copia, viene usato un riferimento alla stessa istanza esistente.

Ecco un esempio, che usa la classe `VideoMode` definita sopra:

```swift
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
```

Questo esempio dichiara una nuova costante chiamata `tenEighty` e la imposta in modo che faccia riferimento a una nuova istanza della classe `VideoMode`. Alla modalità video viene assegnata una copia della risoluzione HD di `1920` per `1080` vista prima. Viene impostata come interlacciata, il suo nome viene impostato a `"1080i"`, e la sua frequenza di fotogrammi viene impostata a `25.0` fotogrammi al secondo.

Successivamente, `tenEighty` viene assegnata a una nuova costante, chiamata `alsoTenEighty`, e la frequenza di fotogrammi di `alsoTenEighty` viene modificata:

```swift
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
```

Poiché le classi sono tipi riferimento, `tenEighty` e `alsoTenEighty` fanno in realtà entrambe riferimento alla *stessa* istanza di `VideoMode`. Di fatto, sono semplicemente due nomi diversi per la stessa unica istanza, come mostrato nella figura seguente:

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

Controllando la proprietà `frameRate` di `tenEighty` si vede che riporta correttamente la nuova frequenza di fotogrammi di `30.0` dall'istanza di `VideoMode` sottostante:

```swift
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// Stampa "The frameRate property of tenEighty is now 30.0".
```

Questo esempio mostra anche come i tipi riferimento possano essere più difficili da comprendere. Se `tenEighty` e `alsoTenEighty` fossero molto distanti nel codice del tuo programma, potrebbe essere difficile trovare tutti i modi in cui la modalità video viene modificata. Ovunque usi `tenEighty`, devi anche pensare al codice che usa `alsoTenEighty`, e viceversa. Al contrario, i tipi valore sono più facili da comprendere perché tutto il codice che interagisce con lo stesso valore si trova vicino nei tuoi file sorgente.

Nota che `tenEighty` e `alsoTenEighty` sono dichiarate come *costanti*, anziché come variabili. Tuttavia, puoi comunque modificare `tenEighty.frameRate` e `alsoTenEighty.frameRate` perché i valori delle costanti `tenEighty` e `alsoTenEighty` in sé non cambiano effettivamente. `tenEighty` e `alsoTenEighty` di per sé non “memorizzano” l'istanza di `VideoMode` — invece, entrambe *fanno riferimento* a un'istanza di `VideoMode` dietro le quinte. È la proprietà `frameRate` della `VideoMode` sottostante a essere modificata, non i valori dei riferimenti costanti a quella `VideoMode`.

### Operatori di identità <a href="#operatori-di-identita" id="operatori-di-identita"></a>

Poiché le classi sono tipi riferimento, è possibile che più costanti e variabili facciano riferimento, dietro le quinte, alla stessa unica istanza di una classe. (Lo stesso non vale per strutture ed enumerazioni, perché vengono sempre copiate quando vengono assegnate a una costante o a una variabile, o passate a una funzione.)

A volte può essere utile scoprire se due costanti o variabili fanno riferimento esattamente alla stessa istanza di una classe. Per consentirlo, Swift fornisce due operatori di identità:

* Identico a (`===`)
* Non identico a (`!==`)

Usa questi operatori per verificare se due costanti o variabili fanno riferimento alla stessa unica istanza:

```swift
if tenEighty === alsoTenEighty {
    print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
// Stampa "tenEighty and alsoTenEighty refer to the same VideoMode instance."
```

Nota che *identico a* (rappresentato da tre segni di uguale, ovvero `===`) non significa la stessa cosa di *uguale a* (rappresentato da due segni di uguale, ovvero `==`). *Identico a* significa che due costanti o variabili di tipo classe fanno riferimento esattamente alla stessa istanza di classe. *Uguale a* significa che due istanze sono considerate uguali o equivalenti nel valore, secondo un significato appropriato di *uguale*, come definito da chi ha progettato il tipo.

Quando definisci le tue strutture e classi personalizzate, è tua responsabilità decidere che cosa rende uguali due istanze. Il processo di definizione delle tue implementazioni degli operatori `==` e `!=` è descritto in [Operatori di equivalenza](/guida-al-linguaggio/operatori-avanzati.md#operatori-di-equivalenza).

### Puntatori <a href="#puntatori" id="puntatori"></a>

Se hai esperienza con C, C++ o Objective-C, potresti sapere che questi linguaggi usano i *puntatori* per riferirsi a indirizzi in memoria. Una costante o una variabile Swift che fa riferimento a un'istanza di un qualche tipo riferimento è simile a un puntatore in C, ma non è un puntatore diretto a un indirizzo in memoria, e non richiede di scrivere un asterisco (`*`) per indicare che stai creando un riferimento. Invece, questi riferimenti sono definiti come qualsiasi altra costante o variabile in Swift. La libreria standard di Swift fornisce tipi puntatore e buffer che puoi usare se hai bisogno di interagire direttamente con i puntatori — vedi [Manual Memory Management](https://developer.apple.com/documentation/swift/swift_standard_library/manual_memory_management).
