> 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/type-casting.md).

# Type casting

Determina il tipo di un valore in fase di esecuzione e forniscigli informazioni di tipo più specifiche.

Il *type casting* (conversione di tipo) è un modo per verificare il tipo di un'istanza, o per trattare quell'istanza come una diversa superclasse o sottoclasse proveniente da un altro punto della sua stessa gerarchia di classi.

In Swift il type casting è implementato con gli operatori `is` e `as`. Questi due operatori forniscono un modo semplice ed espressivo per verificare il tipo di un valore o per convertire un valore in un tipo diverso.

Puoi anche usare il type casting per verificare se un tipo è conforme a un protocollo, come descritto in [Verificare la conformità a un protocollo](/guida-al-linguaggio/protocolli.md#verificare-la-conformita-a-un-protocollo).

## Definire una gerarchia di classi per il type casting <a href="#definire-una-gerarchia-di-classi-per-il-type-casting" id="definire-una-gerarchia-di-classi-per-il-type-casting"></a>

Puoi usare il type casting con una gerarchia di classi e sottoclassi per verificare il tipo di una particolare istanza di classe e per convertire quell'istanza in un'altra classe all'interno della stessa gerarchia. I tre frammenti di codice seguenti definiscono una gerarchia di classi e un array contenente istanze di quelle classi, da usare in un esempio di type casting.

Il primo frammento definisce una nuova classe base chiamata `MediaItem`. Questa classe fornisce funzionalità di base per qualsiasi tipo di elemento che compare in una libreria multimediale digitale. In particolare, dichiara una proprietà `name` di tipo `String`, e un inizializzatore `init(name:)`. (Si presume che tutti gli elementi multimediali, compresi tutti i film e le canzoni, abbiano un nome.)

```swift
class MediaItem {
    var name: String
    init(name: String) {
        self.name = name
    }
}
```

Il frammento successivo definisce due sottoclassi di `MediaItem`. La prima sottoclasse, `Movie`, incapsula informazioni aggiuntive su un film o una pellicola. Aggiunge una proprietà `director` alla classe base `MediaItem`, con un inizializzatore corrispondente. La seconda sottoclasse, `Song`, aggiunge una proprietà `artist` e un inizializzatore alla classe base:

```swift
class Movie: MediaItem {
    var director: String
    init(name: String, director: String) {
        self.director = director
        super.init(name: name)
    }
}

class Song: MediaItem {
    var artist: String
    init(name: String, artist: String) {
        self.artist = artist
        super.init(name: name)
    }
}
```

L'ultimo frammento crea un array costante chiamato `library`, che contiene due istanze di `Movie` e tre istanze di `Song`. Il tipo dell'array `library` viene inferito inizializzandolo con il contenuto di un letterale array. Il controllore dei tipi di Swift è in grado di dedurre che `Movie` e `Song` hanno una superclasse comune, `MediaItem`, e quindi inferisce un tipo `[MediaItem]` per l'array `library`:

```swift
let library = [
    Movie(name: "Casablanca", director: "Michael Curtiz"),
    Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
    Movie(name: "Citizen Kane", director: "Orson Welles"),
    Song(name: "The One And Only", artist: "Chesney Hawkes"),
    Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
// il tipo di "library" viene inferito come [MediaItem]
```

Gli elementi memorizzati in `library` sono ancora, dietro le quinte, istanze di `Movie` e di `Song`. Tuttavia, se iteri sul contenuto di questo array, gli elementi che ricevi sono tipizzati come `MediaItem`, e non come `Movie` o `Song`. Per lavorare con essi nel loro tipo nativo, devi *verificarne* il tipo, o eseguirne il *downcast* a un tipo diverso, come descritto di seguito.

## Verificare il tipo <a href="#verificare-il-tipo" id="verificare-il-tipo"></a>

Usa l'*operatore di verifica del tipo* (`is`) per verificare se un'istanza è di un certo tipo sottoclasse. L'operatore di verifica del tipo restituisce `true` se l'istanza è di quel tipo sottoclasse e `false` se non lo è.

L'esempio seguente definisce due variabili, `movieCount` e `songCount`, che contano il numero di istanze di `Movie` e di `Song` nell'array `library`:

```swift
var movieCount = 0
var songCount = 0

for item in library {
    if item is Movie {
        movieCount += 1
    } else if item is Song {
        songCount += 1
    }
}

print("Media library contains \(movieCount) movies and \(songCount) songs")
// Stampa "Media library contains 2 movies and 3 songs".
```

Questo esempio itera su tutti gli elementi dell'array `library`. A ogni passaggio, il ciclo `for`-`in` imposta la costante `item` al `MediaItem` successivo dell'array.

`item is Movie` restituisce `true` se il `MediaItem` corrente è un'istanza di `Movie` e `false` se non lo è. Analogamente, `item is Song` verifica se l'elemento è un'istanza di `Song`. Al termine del ciclo `for`-`in`, i valori di `movieCount` e `songCount` contengono il conteggio di quante istanze di `MediaItem` sono state trovate per ciascun tipo.

## Downcasting <a href="#downcasting" id="downcasting"></a>

Una costante o una variabile di un certo tipo classe può in realtà fare riferimento, dietro le quinte, a un'istanza di una sottoclasse. Quando ritieni che sia questo il caso, puoi provare a eseguire il *downcast* al tipo sottoclasse con un *operatore di type cast* (`as?` o `as!`).

Poiché il downcasting può fallire, l'operatore di type cast esiste in due forme diverse. La forma condizionale, `as?`, restituisce un valore opzionale del tipo a cui stai cercando di eseguire il downcast. La forma forzata, `as!`, tenta il downcast ed esegue l'unwrapping forzato del risultato come un'unica azione composta.

Usa la forma condizionale dell'operatore di type cast (`as?`) quando non sei sicuro che il downcast avrà successo. Questa forma dell'operatore restituirà sempre un valore opzionale, e il valore sarà `nil` se il downcast non è stato possibile. Questo ti permette di verificare se il downcast ha avuto successo.

Usa la forma forzata dell'operatore di type cast (`as!`) solo quando sei sicuro che il downcast avrà sempre successo. Questa forma dell'operatore attiverà un errore in fase di esecuzione se provi a eseguire il downcast a un tipo classe errato.

L'esempio seguente itera su ciascun `MediaItem` di `library`, e stampa una descrizione appropriata per ciascun elemento. Per farlo, deve accedere a ciascun elemento come un vero `Movie` o `Song`, e non solo come un `MediaItem`. Questo è necessario affinché possa accedere alla proprietà `director` o `artist` di un `Movie` o di una `Song` da usare nella descrizione.

In questo esempio, ciascun elemento dell'array potrebbe essere un `Movie`, oppure potrebbe essere una `Song`. Non sai in anticipo quale classe effettiva usare per ciascun elemento, e quindi è appropriato usare la forma condizionale dell'operatore di type cast (`as?`) per verificare il downcast a ogni passaggio del ciclo:

```swift
for item in library {
    if let movie = item as? Movie {
        print("Movie: \(movie.name), dir. \(movie.director)")
    } else if let song = item as? Song {
        print("Song: \(song.name), by \(song.artist)")
    }
}

// Movie: Casablanca, dir. Michael Curtiz
// Song: Blue Suede Shoes, by Elvis Presley
// Movie: Citizen Kane, dir. Orson Welles
// Song: The One And Only, by Chesney Hawkes
// Song: Never Gonna Give You Up, by Rick Astley
```

L'esempio inizia provando a eseguire il downcast dell'`item` corrente a `Movie`. Poiché `item` è un'istanza di `MediaItem`, è possibile che *possa* essere un `Movie`; allo stesso modo, è anche possibile che possa essere una `Song`, o persino soltanto un `MediaItem` di base. A causa di questa incertezza, la forma `as?` dell'operatore di type cast restituisce un valore *opzionale* quando tenta un downcast a un tipo sottoclasse. Il risultato di `item as? Movie` è di tipo `Movie?`, ovvero “`Movie` opzionale”.

Il downcast a `Movie` fallisce quando viene applicato alle istanze di `Song` nell'array library. Per far fronte a questo, l'esempio qui sopra usa l'optional binding per verificare se il `Movie` opzionale contiene effettivamente un valore (cioè, per scoprire se il downcast ha avuto successo.) Questo optional binding è scritto “`if let movie = item as? Movie`”, e può essere letto come:

“Prova ad accedere a `item` come `Movie`. Se l'operazione ha successo, imposta una nuova costante temporanea chiamata `movie` al valore memorizzato nel `Movie` opzionale restituito.”

Se il downcasting ha successo, le proprietà di `movie` vengono quindi usate per stampare una descrizione di quell'istanza di `Movie`, compreso il nome del suo `director`. Un principio simile viene usato per verificare la presenza di istanze di `Song`, e per stampare una descrizione appropriata (compreso il nome dell'`artist`) ogni volta che nella libreria viene trovata una `Song`.

{% hint style="info" %}
**Nota:** La conversione non modifica effettivamente l'istanza né cambia i suoi valori. L'istanza sottostante resta la stessa; viene semplicemente trattata e acceduta come un'istanza del tipo in cui è stata convertita.
{% endhint %}

## Type casting per Any e AnyObject <a href="#type-casting-per-any-e-anyobject" id="type-casting-per-any-e-anyobject"></a>

Swift fornisce due tipi speciali per lavorare con tipi non specifici:

* `Any` può rappresentare un'istanza di qualsiasi tipo, compresi i tipi funzione.
* `AnyObject` può rappresentare un'istanza di qualsiasi tipo classe.

Usa `Any` e `AnyObject` solo quando hai esplicitamente bisogno del comportamento e delle capacità che forniscono. È sempre meglio essere specifici riguardo ai tipi con cui ti aspetti di lavorare nel tuo codice.

Ecco un esempio di utilizzo di `Any` per lavorare con un insieme di tipi diversi, compresi tipi funzione e tipi non classe. L'esempio crea un array chiamato `things`, che può memorizzare valori di tipo `Any`:

```swift
var things: [Any] = []

things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, \(name)" })
```

L'array `things` contiene due valori `Int`, due valori `Double`, un valore `String`, una tupla di tipo `(Double, Double)`, il film “Ghostbusters”, e un'espressione closure che accetta un valore `String` e restituisce un altro valore `String`.

Per scoprire il tipo specifico di una costante o di una variabile di cui è noto soltanto che è di tipo `Any` o `AnyObject`, puoi usare un pattern `is` o `as` nei casi di un'istruzione `switch`. L'esempio seguente itera sugli elementi dell'array `things` e interroga il tipo di ciascun elemento con un'istruzione `switch`. Diversi casi dell'istruzione `switch` associano il valore corrispondente a una costante del tipo specificato per permettere di stamparne il valore:

```swift
for thing in things {
    switch thing {
    case 0 as Int:
        print("zero as an Int")
    case 0 as Double:
        print("zero as a Double")
    case let someInt as Int:
        print("an integer value of \(someInt)")
    case let someDouble as Double where someDouble > 0:
        print("a positive double value of \(someDouble)")
    case is Double:
        print("some other double value that I don't want to print")
    case let someString as String:
        print("a string value of \"\(someString)\"")
    case let (x, y) as (Double, Double):
        print("an (x, y) point at \(x), \(y)")
    case let movie as Movie:
        print("a movie called \(movie.name), dir. \(movie.director)")
    case let stringConverter as (String) -> String:
        print(stringConverter("Michael"))
    default:
        print("something else")
    }
}

// zero as an Int
// zero as a Double
// an integer value of 42
// a positive double value of 3.14159
// a string value of "hello"
// an (x, y) point at 3.0, 5.0
// a movie called Ghostbusters, dir. Ivan Reitman
// Hello, Michael
```

{% hint style="info" %}
**Nota:** Il tipo `Any` rappresenta valori di qualsiasi tipo, compresi i tipi opzionali. Swift ti dà un avviso se usi un valore opzionale dove è previsto un valore di tipo `Any`. Se hai davvero bisogno di usare un valore opzionale come valore `Any`, puoi usare l'operatore `as` per convertire esplicitamente l'opzionale in `Any`, come mostrato di seguito.

```swift
let optionalNumber: Int? = 3
things.append(optionalNumber)        // Avviso
things.append(optionalNumber as Any) // Nessun avviso
```

{% endhint %}
