I parametri "var" sono obsoleti e verranno rimossi in Swift 3


120

Va bene, aggiorno Xcode alla 7.3 e ora ricevo questo avviso:

I parametri "var" sono obsoleti e verranno rimossi in Swift 3

Come risolvere questo problema quando ho bisogno di usare la var in questa funzione:

public func getQuestionList(var language: String) -> NSArray {
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

6
Che ne dicipublic func getQuestionList(inout language: String) -> NSArray
TotoroTotoro

2
No, questo non è un sostituto adatto. Probabilmente OP non vuole getQuestionavere effetti collaterali.
Ballpoint

5
Onestamente non ho idea del motivo per cui avrebbero preso in considerazione la possibilità di rimuoverlo. È stata una delle caratteristiche che ha reso Swift fantastico!
Danny Bravo

Non l'ho mai usato da solo e non capisco il clamore.
Mike Taverne

@MikeTaverne (ritardo di risposta) Si consideri la seguente funzione: func foo(_ bar: int) { /*use bar*/ bar+=1; foo(bar); }. Questo è impossibile senza var params. È necessario creare una var separata all'interno della funzione e copiare il valore o contrassegnare il parametro come inout. Il primo è lento, il secondo provoca un comportamento indefinito. Molti algoritmi usano la ricorsione in questo modo.
kevin

Risposte:


82

Hai provato ad assegnare a una nuova var

public func getQuestionList(language: String) -> NSArray {
    var lang = language
    if self.data.count > 0 {
        if (lang.isEmpty) {
            lang = "NL"
        }
        return self.data.objectForKey("questionList" + lang) as! NSArray
    }

    return NSArray()
}

11
Non proprio quello che penso volesse l'OP
zolfo il

6
Avrei capito la domanda di OP allo stesso modo di @garana. OP non usa inout nella loro domanda, si limita a mutare localmente una variabile preesistente .
Eric Aya

11
In realtà questa è la soluzione corretta. Si prega di consultare il numero di evoluzione di Swift che ha proposto questa modifica: github.com/apple/swift-evolution/blob/master/proposals/…
Scott Thompson

8
@TimVermeulen Tutti vogliono usare un linguaggio progressivo. Apple può sviluppare il proprio linguaggio in molti modi, non cambiando la sintassi ogni singolo mese. Come sai, un sacco di documenti online e frammenti di codice sono scaduti o obsoleti a causa di Apple. Gli sviluppatori devono venire su questo sito per chiedere aiuto con molte domande stupide ripetutamente a causa di ciò. La sintassi deve essere solida fin dall'inizio se Apple vuole che più sviluppatori siano bravi.
TomSawyer

25
Usa var language = language, se non vuoi introdurre un altro nome di variabile (che era il principale vantaggio del parametro var in primo luogo imo)
Harris

102

La discussione sulla rimozione di Var da un parametro di funzione è completamente documentata in questa presentazione su GitHub: Remove Var Parameters

In quel documento scoprirai che le persone spesso confondono i varparametri con i inoutparametri. Un varparametro significa semplicemente che il parametro è modificabile all'interno del contesto della funzione, mentre con un inoutparametro il valore del parametro nel punto di ritorno verrà copiato fuori dalla funzione e nel contesto del chiamante.

Il modo corretto per risolvere questo problema è rimuovere vardal parametro e introdurre una varvariabile locale . Nella parte superiore della routine copia il valore del parametro in quella variabile.


44
Non capisco affatto questo cambiamento, perché dover scrivere un'altra riga per creare una var locale mutabile sarebbe meglio che definire semplicemente il parametro come var?
Ross Barbish

Per me questo cambiamento è positivo perché sta raccogliendo situazioni in cui avrei dovuto implementare una variabile locale ma non l'ho fatto perché ho preso la via più facile e ho accettato il (vecchio) suggerimento di Swift di rendere il parametro di input una
variabile

1
Sono con @RossBarbish su questo. Quindi ... questo è stato rimosso perché gli sviluppatori pigri non possono distinguere tra i parametri inout e var? Pfff ...
Danny Bravo

1
Questo sembra terribilmente inutile ..., avrebbero dovuto mantenere entrambe le opzioni.
Oscar Gomez

1
Probabilmente swift stava comunque dichiarando una variabile locale sopra il parametro dietro le quinte. Ora dobbiamo farlo manualmente. Nessun cambiamento nelle prestazioni, ma abbiamo perso la comodità di aiutare i principianti con un concetto semplice.
mogelbuster

62

Basta aggiungere questa una riga all'inizio della funzione:

var language = language

e il resto del codice può rimanere invariato, in questo modo:

public func getQuestionList(language: String) -> NSArray {
    var language = language
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

5
La migliore risposta in assoluto. Richiede solo la modifica di una riga.
Ballpoint

Ma sembra così innaturale @James
asyncwait

1
Penso che questa sia la risposta migliore in quanto mantiene lo stesso nome. Simile a come lo fanno altre lingue comuni.
eonista

1
@RiverSatya Perché non utilizzare direttamente il parametro?
Declan McKenna

1
Davvero un fantastico suggerimento. Lo implementeremo in questo modo in Swiftify :)
Crulex

13

Molte persone suggeriscono un inoutparametro, ma in realtà non è quello per cui sono progettati. Inoltre, non consente di chiamare la funzione con una letcostante, né con una stringa letterale. Perché non aggiungi semplicemente il valore predefinito alla firma della funzione?

public func getQuestionList(language language: String = "NL") -> NSArray {
    if data.count > 0 {
        return data.objectForKey("questionList" + language) as! NSArray
    } else {
        return NSArray()
    }
}

Assicurati solo di non chiamare getQuestionListcon la stringa vuota nel caso in cui desideri la lingua predefinita, ma lascia fuori il parametro:

let list = getQuestionList() // uses the default "NL" language

3
Inoltre non capisco perché tutti siano passati alla soluzione inout quando OP non la usava nemmeno all'inizio ...
Eric Aya

1
Presumevano che var e inout facessero la stessa cosa.
ryantxr

2

Swift 4

public func getQuestionList(language: inout String) -> NSArray {
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

getQuestionList(language: &someString)

In alcuni casi, come ho sperimentato (con configurazioni più complesse che coinvolgono array), la creazione di una nuova proprietà all'interno del metodo e la modifica di tale proprietà potrebbero non funzionare sempre. Per non parlare del fatto che stai ingombrando il metodo invece di aggiungerlo semplicemente inouta un parametro e &al suo argomento, che è ciò per cui è stata creata questa sintassi.



0

Penso che le risposte di @Harris e @garanda siano l'approccio migliore.

Comunque nel tuo caso non c'è bisogno di una var, puoi fare:

public func getQuestionList(language: String) -> NSArray {
    if self.data.count > 0 {
        return self.data.objectForKey("questionList" + (language.isEmpty ? "NL" : language)) as! NSArray
    }
    return NSArray()
}

0

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html

Parametri in-out

I parametri della funzione sono costanti per impostazione predefinita. Il tentativo di modificare il valore di un parametro di funzione dall'interno del corpo di tale funzione genera un errore in fase di compilazione. Ciò significa che non è possibile modificare per errore il valore di un parametro. Se si desidera che una funzione modifichi il valore di un parametro e si desidera che tali modifiche persistano al termine della chiamata alla funzione, definire invece quel parametro come un parametro in-out.

Scrivi un parametro in-out posizionando la parola chiave inout subito prima del tipo di parametro. Un parametro in-out ha un valore che viene passato alla funzione, viene modificato dalla funzione e viene ritrasmesso fuori dalla funzione per sostituire il valore originale. Per una discussione dettagliata del comportamento dei parametri in-out e delle ottimizzazioni del compilatore associate, vedere In-Out Parameters.

È possibile passare una variabile solo come argomento per un parametro in-out. Non è possibile passare una costante o un valore letterale come argomento, perché costanti e letterali non possono essere modificati. Si inserisce una e commerciale (&) direttamente prima del nome di una variabile quando la si passa come argomento a un parametro in-out, per indicare che può essere modificata dalla funzione.

NOTA

I parametri in-out non possono avere valori predefiniti e i parametri variadic non possono essere contrassegnati come inout.

Ecco un esempio di una funzione chiamata swapTwoInts ( : :), che ha due parametri interi in-out chiamati aeb:

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

La funzione swapTwoInts ( : :) scambia semplicemente il valore di b in a e il valore di a in b. La funzione esegue questo scambio memorizzando il valore di a in una costante temporanea chiamata temporaryA, assegnando il valore di b ad a, e quindi assegnando temporaryA a b.

Puoi chiamare la funzione swapTwoInts ( : :) con due variabili di tipo Int per scambiare i loro valori. Si noti che i nomi di someInt e anotherInt sono preceduti da una e commerciale quando vengono passati alla funzione swapTwoInts ( : :):

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"

L'esempio sopra mostra che i valori originali di someInt e anotherInt vengono modificati da swapTwoInts ( : :), anche se originariamente erano definiti al di fuori della funzione.

NOTA

I parametri in-out non sono la stessa cosa che restituire un valore da una funzione. L'esempio swapTwoInts precedente non definisce un tipo di ritorno o restituisce un valore, ma modifica comunque i valori di someInt e anotherInt. I parametri in-out sono un modo alternativo per una funzione di avere un effetto al di fuori dell'ambito del suo corpo di funzione.


0

Ecco un'altra idea. Il mio caso d'uso è stato quello di passare un array di stringhe da aggiungere ad esso, per cui l'array deve essere passato in modo mutevole. Neanche per questo volevo avere uno stato nella mia classe. Quindi ho creato una classe che contiene l'array e l'ho passata. A seconda del tuo caso d'uso, potrebbe sembrare sciocco avere una classe che contiene solo quella variabile.

private class StringBuilder {
    var buffer: [String] = []

    func append(_ str: String) {
        buffer.append(str)
    }

    func toString() -> String {
        return buffer.joined()
    }
}

Uso solo appendjoined metodi e sull'array, quindi è stato facile cambiare il tipo con altre modifiche minime al mio codice.

Alcuni esempi di utilizzo:

private func writeMap(map: LevelMap, url: URL) -> Bool {
    let buffer = StringBuilder()

    if !writeHeader(map: map, buffer: buffer) {
        return false
    }
    if !writeFloors(map: map, buffer: buffer) {
        return false
    }

    let content = buffer.toString()
    do {
        try content.write(to: url, atomically: true, encoding: .utf8)
        return true
    } catch {}
    return false
}

private func writeHeader(map: LevelMap, buffer: StringBuilder) -> Bool {
    buffer.append("something here ...\n")
    return true
}

La mia risposta è se VUOI che il valore originale visto dal chiamante venga modificato. Se volevi solo essere in grado di riassegnare localmente il valore ma non farlo influenzare il chiamante, altre risposte sopra si occupano di questo.
webjprgm
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.