Swift rende mutabile il parametro del metodo?


123

Come posso gestire questo errore senza creare una variabile aggiuntiva?

func reduceToZero(x:Int) -> Int {
    while (x != 0) {
        x = x-1            // ERROR: cannot assign to 'let' value 'x'
    }
    return x
}

Non voglio creare una variabile aggiuntiva solo per memorizzare il valore di x. È anche possibile fare quello che voglio?


3
Vedi le risposte aggiornate di seguito, Swift 3 ha deprecato la tua risposta accettata.
achi

Risposte:


192

Come affermato in altre risposte, a partire da Swift 3 posizionare var prima di una variabile è stato deprecato. Sebbene non sia dichiarato in altre risposte, è la capacità di dichiarare un inoutparametro. Pensa: passare un puntatore.

func reduceToZero(_ x: inout Int) {
    while (x != 0) {
        x = x-1     
    }
}

var a = 3
reduceToZero(&a)
print(a) // will print '0'

Questo può essere particolarmente utile nella ricorsione.

Le inoutlinee guida per la dichiarazione di Apple possono essere trovate qui .


2
Grazie mille!!!! Sono bloccato qui su una domanda di ricorsione. Mi hai salvato la vita.
JW.ZG

2
Dovrebbe usarlo con cautela poiché modifica le variabili al di fuori dell'ambito della funzione. Idealmente si desidera restituire esplicitamente il valore modificato all'interno della funzione.
Chris Gunawardena

2
inoutla parola chiave deve essere inserita tra il nome e il tipo di parametro in questo modo: func reduceToZero(x: inout Int) nella versione corrente di Swift 3.
Agustí Sánchez

Tranne che questo non sembra funzionare per le chiusure poiché le chiusure evidentemente catturano solo i parametri inout per valore (almeno questo è il messaggio di errore che Xcode mi dà). In questo caso utilizzo la soluzione @GeRyCh.
wcochran

Grazie. Per ora ha funzionato, ma è come usare i puntatori in C. Questo sopravviverà a un'altra versione di Swift?
Krishna Vedula

45

I parametri "var" sono deprecati e verranno rimossi in Swift 3. Quindi l'assegnazione di un nuovo parametro sembra il modo migliore ora:

func reduceToZero(x:Int) -> Int {
    var x = x
    while (x != 0) {
        x = x-1            
    }
    return x
}

come menzionato qui: i parametri "var" sono deprecati e verranno rimossi in Swift 3


1
In questo caso, copia effettivamente il xnel nuovo var x? O Swift sta facendo qualcosa di più efficiente di così?
Genki

3
Questo funziona ed è quello che faccio, ma sembra molto imbarazzante.
wcochran

1
@Gomfucius Non una parola su questo nella guida Swift 3.1. In questo caso (si xinserisce nel registro) non c'è praticamente alcun costo. Se xè array, struct, o un oggetto che è mutato, poi una copia quasi certamente deve essere eseguita (a meno che l'ottimizzatore può analizzarlo in linea e alias di esso).
wcochran

1
@wcochran Questo è un bel trucco, ma in realtà non sta succedendo niente di speciale. Sta semplicemente eclissando un parametro di input con una copia var locale. Nella situazione del PO è un sostituto migliore per gli varargomenti rispetto all'uso inoutche potrebbe avere effetti collaterali non intenzionali, specialmente. se la var fosse un puntatore.
Echelon

45

Per Swift 1 e 2 (per Swift 3 vedere la risposta di achi utilizzando un parametro inout): L'argomento di una funzione in Swift è letpredefinito, quindi modificalo varse devi modificare il valore, ad es.

func reduceToZero(var x:Int) -> Int {
    while (x != 0) {
        x = x-1     
    }
    return x
}

2
Perché questa risposta è votata come l'inferno? L'altra risposta è stata posta prima di questa e contiene più informazioni di questa.
Cristik

16
/! \ L'uso di var creerà una copia della variabile passata nei parametri. Quindi modificarlo non modificherà il valore originale. Anche varnei parametri è molto probabile che scompaia nelle nuove versioni di Swift per github.com/apple/swift-evolution/blob/master/proposals/…
Matthieu Riegler

17
La parola chiave var nel metodo paremeter sarà deprecata in Swift 3.
Boon

4
Penso che con Swift 3 non saremo più in grado di farlo. Dovremo creare una copia variabile dell'array e restituire l'array modificato.
C0D3

Questa risposta è la risposta corretta: stackoverflow.com/questions/24077880/…
achi

14

Risposta rapida 3 per il passaggio del puntatore a matrice mutabile.

Funzione:

func foo(array: inout Array<Int>) {
    array.append(1)
}

Chiamata alla funzione:

var a = Array<Int>()
foo(array:&a)

Onestamente, non sono sicuro che sia corretto poiché il terreno di Swift è in continua evoluzione. Ho pensato che fosse meglio che fare var array = array all'interno della funzione perché ciò fa una copia (e in realtà non influisce sulla struttura dell'array originale)? È un approccio di progettazione migliore al suddetto approccio var e quindi restituisce il nuovo array mutato?
joshd

7

In Swift devi semplicemente aggiungere la varparola chiave prima del nome della variabile nella dichiarazione della funzione:

func reduceToZero(var x:Int) -> Int { // notice the "var" keyword
    while (x != 0) {
        x = x-1            
    }
    return x
}

Fare riferimento alla sottosezione "Parametri costanti e variabili" nel capitolo "Funzioni" del libro Swift (pagina 210 dell'iBook come è oggi).


7
I parametri "var" sono obsoleti e verranno rimossi in Swift 3
Regis St-Gelais

1
Non valido per Swift 4 e versioni successive.
ilkayaktas

0

Ci sono alcuni casi in cui non è stato necessario utilizzare inout

Possiamo usare qualcosa di simile se vuoi che le modifiche / l'ambito siano solo all'interno della funzione:

func manipulateData(a: Int) -> Int {
    var a = a
    // ...
}

0

Soluzione che utilizza Swift5 con la programmazione funzionale ...

func reduceToZeroFP(x:Int) -> Int {
    x == 0 ? x : reduceToZeroFP(x: x - 1)
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.