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

# Metodi (Methods)

Definisci e chiama funzioni che fanno parte di un'istanza o di un tipo.

I *metodi* sono funzioni associate a un tipo particolare. Classi, strutture ed enumerazioni possono tutte definire metodi di istanza, che incapsulano compiti e funzionalità specifici per lavorare con un'istanza di un dato tipo. Classi, strutture ed enumerazioni possono anche definire metodi di tipo, che sono associati al tipo stesso. I metodi di tipo sono simili ai metodi di classe di Objective-C.

Il fatto che in Swift strutture ed enumerazioni possano definire metodi è una differenza importante rispetto a C e Objective-C. In Objective-C, le classi sono gli unici tipi che possono definire metodi. In Swift, puoi scegliere se definire una classe, una struttura o un'enumerazione, e avere comunque la flessibilità di definire metodi sul tipo che crei.

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

I *metodi di istanza* sono funzioni che appartengono alle istanze di una particolare classe, struttura o enumerazione. Supportano la funzionalità di quelle istanze, fornendo modi per accedere alle proprietà di istanza e modificarle, oppure fornendo funzionalità legate allo scopo dell'istanza. I metodi di istanza hanno esattamente la stessa sintassi delle funzioni, come descritto in [Funzioni](/guida-al-linguaggio/funzioni.md).

Scrivi un metodo di istanza all'interno delle parentesi graffe di apertura e di chiusura del tipo a cui appartiene. Un metodo di istanza ha accesso implicito a tutti gli altri metodi e proprietà di istanza di quel tipo. Un metodo di istanza può essere chiamato solo su una specifica istanza del tipo a cui appartiene. Non può essere chiamato in modo isolato senza un'istanza esistente.

Ecco un esempio che definisce una semplice classe `Counter`, che può essere usata per contare il numero di volte in cui si verifica un'azione:

```swift
class Counter {
    var count = 0
    func increment() {
        count += 1
    }
    func increment(by amount: Int) {
        count += amount
    }
    func reset() {
        count = 0
    }
}
```

La classe `Counter` definisce tre metodi di istanza:

* `increment()` incrementa il contatore di `1`.
* `increment(by: Int)` incrementa il contatore di una quantità intera specificata.
* `reset()` azzera il contatore.

La classe `Counter` dichiara inoltre una proprietà variabile, `count`, per tenere traccia del valore corrente del contatore.

Chiami i metodi di istanza con la stessa sintassi a punto delle proprietà:

```swift
let counter = Counter()
// il valore iniziale del contatore è 0
counter.increment()
// il valore del contatore ora è 1
counter.increment(by: 5)
// il valore del contatore ora è 6
counter.reset()
// il valore del contatore ora è 0
```

I parametri di una funzione possono avere sia un nome (da usare all'interno del corpo della funzione) sia un'etichetta dell'argomento (da usare quando si chiama la funzione), come descritto in [Etichette degli argomenti e nomi dei parametri delle funzioni](/guida-al-linguaggio/funzioni.md#etichette-degli-argomenti-e-nomi-dei-parametri-delle-funzioni). Lo stesso vale per i parametri dei metodi, perché i metodi sono semplicemente funzioni associate a un tipo.

### La proprietà self <a href="#la-proprieta-self" id="la-proprieta-self"></a>

Ogni istanza di un tipo ha una proprietà implicita chiamata `self`, che è esattamente equivalente all'istanza stessa. Usi la proprietà `self` per riferirti all'istanza corrente all'interno dei suoi stessi metodi di istanza.

Il metodo `increment()` dell'esempio qui sopra avrebbe potuto essere scritto così:

```swift
func increment() {
    self.count += 1
}
```

In pratica, non hai bisogno di scrivere `self` nel tuo codice molto spesso. Se non scrivi esplicitamente `self`, Swift presume che tu ti stia riferendo a una proprietà o a un metodo dell'istanza corrente ogni volta che usi il nome di una proprietà o di un metodo noto all'interno di un metodo. Questa supposizione è dimostrata dall'uso di `count` (anziché `self.count`) all'interno dei tre metodi di istanza di `Counter`.

La principale eccezione a questa regola si verifica quando il nome di un parametro di un metodo di istanza coincide con il nome di una proprietà di quell'istanza. In questa situazione, il nome del parametro ha la precedenza, e diventa necessario riferirsi alla proprietà in modo più qualificato. Usi la proprietà `self` per distinguere tra il nome del parametro e il nome della proprietà.

Qui, `self` elimina l'ambiguità tra un parametro del metodo chiamato `x` e una proprietà di istanza chiamata anch'essa `x`:

```swift
struct Point {
    var x = 0.0, y = 0.0
    func isToTheRightOf(x: Double) -> Bool {
        return self.x > x
    }
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOf(x: 1.0) {
    print("This point is to the right of the line where x == 1.0")
}
// Stampa "This point is to the right of the line where x == 1.0".
```

Senza il prefisso `self`, Swift presumerebbe che entrambi gli usi di `x` si riferiscano al parametro del metodo chiamato `x`.

### Modificare i tipi valore dall'interno dei metodi di istanza <a href="#modificare-i-tipi-valore-dallinterno-dei-metodi-di-istanza" id="modificare-i-tipi-valore-dallinterno-dei-metodi-di-istanza"></a>

Strutture ed enumerazioni sono *tipi valore*. Per impostazione predefinita, le proprietà di un tipo valore non possono essere modificate dall'interno dei suoi metodi di istanza.

Tuttavia, se hai bisogno di modificare le proprietà della tua struttura o enumerazione all'interno di un metodo particolare, puoi scegliere di abilitare il comportamento *mutating* per quel metodo. Il metodo può quindi mutare (cioè cambiare) le sue proprietà dall'interno del metodo, e qualsiasi modifica che apporta viene riscritta nella struttura originale quando il metodo termina. Il metodo può anche assegnare un'istanza completamente nuova alla sua proprietà implicita `self`, e questa nuova istanza sostituirà quella esistente quando il metodo termina.

Puoi abilitare questo comportamento inserendo la parola chiave `mutating` prima della parola chiave `func` di quel metodo:

```swift
struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// Stampa "The point is now at (3.0, 4.0)".
```

La struttura `Point` qui sopra definisce un metodo mutating `moveBy(x:y:)`, che sposta un'istanza di `Point` di una certa quantità. Invece di restituire un nuovo punto, questo metodo modifica effettivamente il punto su cui viene chiamato. La parola chiave `mutating` viene aggiunta alla sua definizione per permettergli di modificare le sue proprietà.

Nota che non puoi chiamare un metodo mutating su una costante di tipo struttura, perché le sue proprietà non possono essere cambiate, anche se sono proprietà variabili, come descritto in [Proprietà memorizzate di istanze costanti di strutture](/guida-al-linguaggio/proprieta.md#proprieta-memorizzate-di-istanze-costanti-di-strutture):

```swift
let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveBy(x: 2.0, y: 3.0)
// questo segnalerà un errore
```

### Assegnare a self all'interno di un metodo mutating <a href="#assegnare-a-self-allinterno-di-un-metodo-mutating" id="assegnare-a-self-allinterno-di-un-metodo-mutating"></a>

I metodi mutating possono assegnare un'istanza completamente nuova alla proprietà implicita `self`. L'esempio `Point` mostrato sopra avrebbe potuto invece essere scritto nel modo seguente:

```swift
struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        self = Point(x: x + deltaX, y: y + deltaY)
    }
}
```

Questa versione del metodo mutating `moveBy(x:y:)` crea una nuova struttura i cui valori `x` e `y` sono impostati sulla posizione di destinazione. Il risultato finale della chiamata a questa versione alternativa del metodo sarà esattamente lo stesso della chiamata alla versione precedente.

I metodi mutating delle enumerazioni possono impostare il parametro implicito `self` su un caso diverso della stessa enumerazione:

```swift
enum TriStateSwitch {
    case off, low, high
    mutating func next() {
        switch self {
        case .off:
            self = .low
        case .low:
            self = .high
        case .high:
            self = .off
        }
    }
}
var ovenLight = TriStateSwitch.low
ovenLight.next()
// ovenLight ora è uguale a .high
ovenLight.next()
// ovenLight ora è uguale a .off
```

Questo esempio definisce un'enumerazione per un interruttore a tre stati. L'interruttore passa ciclicamente fra tre diversi stati di alimentazione (`off`, `low` e `high`) ogni volta che viene chiamato il suo metodo `next()`.

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

I metodi di istanza, come descritti sopra, sono metodi che chiami su un'istanza di un tipo particolare. Puoi anche definire metodi che vengono chiamati sul tipo stesso. Questo genere di metodi è chiamato *metodi di tipo*. Indichi i metodi di tipo scrivendo la parola chiave `static` prima della parola chiave `func` del metodo. Le classi possono invece usare la parola chiave `class`, per consentire alle sottoclassi di sovrascrivere l'implementazione di quel metodo della superclasse.

{% hint style="info" %}
**Nota:** In Objective-C, puoi definire metodi a livello di tipo solo per le classi Objective-C. In Swift, puoi definire metodi a livello di tipo per tutte le classi, le strutture e le enumerazioni. Ogni metodo di tipo ha un ambito esplicitamente limitato al tipo che supporta.
{% endhint %}

I metodi di tipo si chiamano con la sintassi a punto, come i metodi di istanza. Tuttavia, i metodi di tipo si chiamano sul tipo, non su un'istanza di quel tipo. Ecco come chiami un metodo di tipo su una classe chiamata `SomeClass`:

```swift
class SomeClass {
    class func someTypeMethod() {
        // qui va l'implementazione del metodo di tipo
    }
}
SomeClass.someTypeMethod()
```

All'interno del corpo di un metodo di tipo, la proprietà implicita `self` si riferisce al tipo stesso, anziché a un'istanza di quel tipo. Ciò significa che puoi usare `self` per eliminare l'ambiguità tra proprietà di tipo e parametri dei metodi di tipo, proprio come fai per le proprietà di istanza e i parametri dei metodi di istanza.

Più in generale, qualsiasi nome non qualificato di metodo e di proprietà che usi all'interno del corpo di un metodo di tipo si riferirà ad altri metodi e proprietà a livello di tipo. Un metodo di tipo può chiamare un altro metodo di tipo con il nome dell'altro metodo, senza bisogno di anteporgli il nome del tipo. Analogamente, i metodi di tipo di strutture ed enumerazioni possono accedere alle proprietà di tipo usando il nome della proprietà di tipo senza il prefisso del nome del tipo.

L'esempio seguente definisce una struttura chiamata `LevelTracker`, che tiene traccia dei progressi di un giocatore attraverso i diversi livelli o fasi di un gioco. È un gioco per giocatore singolo, ma può memorizzare informazioni per più giocatori su un unico dispositivo.

Tutti i livelli del gioco (eccetto il livello uno) sono bloccati quando si gioca per la prima volta. Ogni volta che un giocatore completa un livello, quel livello viene sbloccato per tutti i giocatori sul dispositivo. La struttura `LevelTracker` usa proprietà e metodi di tipo per tenere traccia di quali livelli del gioco sono stati sbloccati. Tiene inoltre traccia del livello corrente di un singolo giocatore.

```swift
struct LevelTracker {
    static var highestUnlockedLevel = 1
    var currentLevel = 1

    static func unlock(_ level: Int) {
        if level > highestUnlockedLevel { highestUnlockedLevel = level }
    }

    static func isUnlocked(_ level: Int) -> Bool {
        return level <= highestUnlockedLevel
    }

    @discardableResult
    mutating func advance(to level: Int) -> Bool {
        if LevelTracker.isUnlocked(level) {
            currentLevel = level
            return true
        } else {
            return false
        }
    }
}
```

La struttura `LevelTracker` tiene traccia del livello più alto che un qualsiasi giocatore ha sbloccato. Questo valore è memorizzato in una proprietà di tipo chiamata `highestUnlockedLevel`.

`LevelTracker` definisce anche due funzioni di tipo per lavorare con la proprietà `highestUnlockedLevel`. La prima è una funzione di tipo chiamata `unlock(_:)`, che aggiorna il valore di `highestUnlockedLevel` ogni volta che viene sbloccato un nuovo livello. La seconda è una funzione di tipo di utilità chiamata `isUnlocked(_:)`, che restituisce `true` se un particolare numero di livello è già sbloccato. (Nota che questi metodi di tipo possono accedere alla proprietà di tipo `highestUnlockedLevel` senza che tu debba scriverla come `LevelTracker.highestUnlockedLevel`.)

Oltre alla sua proprietà di tipo e ai suoi metodi di tipo, `LevelTracker` tiene traccia dei progressi di un singolo giocatore nel gioco. Usa una proprietà di istanza chiamata `currentLevel` per tenere traccia del livello a cui un giocatore sta giocando attualmente.

Per aiutare a gestire la proprietà `currentLevel`, `LevelTracker` definisce un metodo di istanza chiamato `advance(to:)`. Prima di aggiornare `currentLevel`, questo metodo verifica se il nuovo livello richiesto è già sbloccato. Il metodo `advance(to:)` restituisce un valore booleano per indicare se sia stato effettivamente in grado di impostare `currentLevel` o meno. Poiché non è necessariamente un errore per il codice che chiama il metodo `advance(to:)` ignorare il valore di ritorno, questa funzione è contrassegnata con l'attributo `@discardableResult`. Per maggiori informazioni su questo attributo, vedi [Attributi](/riferimento-del-linguaggio/attributi.md).

La struttura `LevelTracker` viene usata con la classe `Player`, mostrata di seguito, per tenere traccia dei progressi di un singolo giocatore e aggiornarli:

```swift
class Player {
    var tracker = LevelTracker()
    let playerName: String
    func complete(level: Int) {
        LevelTracker.unlock(level + 1)
        tracker.advance(to: level + 1)
    }
    init(name: String) {
        playerName = name
    }
}
```

La classe `Player` crea una nuova istanza di `LevelTracker` per tenere traccia dei progressi di quel giocatore. Fornisce inoltre un metodo chiamato `complete(level:)`, che viene chiamato ogni volta che un giocatore completa un livello particolare. Questo metodo sblocca il livello successivo per tutti i giocatori e aggiorna i progressi del giocatore per spostarlo al livello successivo. (Il valore di ritorno booleano di `advance(to:)` viene ignorato, perché è noto che il livello è stato sbloccato dalla chiamata a `LevelTracker.unlock(_:)` alla riga precedente.)

Puoi creare un'istanza della classe `Player` per un nuovo giocatore, e vedere che cosa succede quando il giocatore completa il livello uno:

```swift
var player = Player(name: "Argyrios")
player.complete(level: 1)
print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// Stampa "highest unlocked level is now 2".
```

Se crei un secondo giocatore, che provi a spostare a un livello non ancora sbloccato da alcun giocatore nel gioco, il tentativo di impostare il livello corrente del giocatore fallisce:

```swift
player = Player(name: "Beto")
if player.tracker.advance(to: 6) {
    print("player is now on level 6")
} else {
    print("level 6 hasn't yet been unlocked")
}
// Stampa "level 6 hasn't yet been unlocked".
```
