Parametry „var” są przestarzałe i zostaną usunięte w języku Swift 3

120

W porządku, więc po prostu zaktualizowałem Xcode do 7.3 i teraz otrzymuję to ostrzeżenie:

Parametry „var” są przestarzałe i zostaną usunięte w języku Swift 3

Jak to naprawić, gdy muszę użyć var ​​w tej funkcji:

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()
}
SDW
źródło
6
Co powiesz napublic func getQuestionList(inout language: String) -> NSArray
TotoroTotoro
2
Nie, to nie jest odpowiedni zamiennik. OP prawdopodobnie nie chce getQuestionmieć żadnych skutków ubocznych.
BallpointBen
5
Szczerze mówiąc, nie mam pojęcia, dlaczego w ogóle rozważali usunięcie tego. To była jedna z cech, która sprawiła, że ​​szybki był niesamowity!
Danny Bravo,
Sam go nigdy nie używałem i nie rozumiem tego zamieszania.
Mike Taverne
@MikeTaverne (późna odpowiedź) Rozważmy następującą funkcję: func foo(_ bar: int) { /*use bar*/ bar+=1; foo(bar); }. Jest to niemożliwe bez var params. Musisz albo utworzyć oddzielną zmienną w funkcji i skopiować wartość, albo oznaczyć parametr jako inout. Pierwsza jest powolna, druga powoduje niezdefiniowane zachowanie. Wiele algorytmów używa takiej rekurencji.
kevin

Odpowiedzi:

82

Czy próbowałeś przypisać do nowego 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()
}
garanda
źródło
11
Myślę, że nie to, czego chciał OP
siatka
6
Zrozumiałbym pytanie OP tak samo, jak @garana. OP nie używa inout w swoim pytaniu, po prostu mutują lokalnie istniejącą zmienną .
Eric Aya
11
Właściwie to jest właściwe rozwiązanie. Zapoznaj się z problemem dotyczącym szybkiej
Scott Thompson
8
@TimVermeulen Każdy chce używać progresywnego języka. Apple może rozwijać swój język na wiele sposobów, nie zmieniając składni co miesiąc. Jak wiesz, mnóstwo dokumentów online i fragmentów kodu straciło ważność lub stało się nieaktualne z powodu Apple. Z tego powodu programiści muszą przychodzić na tę stronę, aby wielokrotnie prosić o pomoc przy wielu głupich pytaniach. Składnia musi być solidna od samego początku, jeśli Apple chce, aby więcej programistów było w tym dobrych.
TomSawyer
25
Użyj var language = language, jeśli nie chcesz wprowadzać innej nazwy zmiennej (co było główną zaletą parametru var w pierwszej kolejności imo)
Harris
102

Omówienie usunięcia Var z parametru funkcji jest w pełni udokumentowane w tym przesłaniu na GitHub: Remove Var Parameters

W tym dokumencie zobaczysz, że ludzie często mylą varparametry z inoutparametrami. varParametrów oznacza, że parametr jest zmienne w odniesieniu do funkcji, a ze związkieminout parametrem wartość parametru w punkcie zwrotu zostaną skopiowane z funkcji i w kontekście rozmówcy.

Prawidłowym sposobem rozwiązania tego problemu jest usunięcie varz parametru i wprowadzenie varzmiennej lokalnej . W górnej części procedury skopiuj wartość parametru do tej zmiennej.

Tr0yJ
źródło
44
W ogóle nie rozumiem tej zmiany, dlaczego konieczność napisania kolejnej linii w celu utworzenia zmiennej lokalnej zmiennej byłaby lepsza niż po prostu zdefiniowanie parametru jako zmiennej?
Ross Barbish
Dla mnie ta zmiana jest dobra, ponieważ wychwytuje sytuacje, w których powinienem był zaimplementować zmienną lokalną, ale nie zrobiłem tego, ponieważ wybrałem łatwe wyjście i zaakceptowałem (starą) sugestię Swifta, aby zmienić parametr wejściowy jako var
dawid
1
Jestem z @ RossBarbish w tej sprawie. Więc ... to jest usuwane, ponieważ leniwi programiści nie mogą odróżnić parametrów inout i var? Pfff ...
Danny Bravo
1
Wydaje się to strasznie niepotrzebne ... Powinni byli zachować obie opcje.
Oscar Gomez
1
Prawdopodobnie Swift i tak deklarował lokalną zmienną nad parametrem za kulisami. Teraz musimy to zrobić ręcznie. Bez zmian w wydajności, ale straciliśmy wygodę, aby pomóc początkującym dzięki prostej koncepcji.
mogelbuster
62

Po prostu dodaj tę jedną linię na początku funkcji:

var language = language

a reszta kodu może pozostać niezmieniona, na przykład:

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()
}
Harris
źródło
5
Zdecydowanie najlepsza odpowiedź. Wymaga tylko zmiany jednej linii.
BallpointBen
Ale wygląda tak nienaturalnie @James
asyncwait
1
Uważam, że to najlepsza odpowiedź, ponieważ zachowuje tę samą nazwę. Podobnie jak robią to inne popularne języki.
eonista
1
@RiverSatya Dlaczego po prostu nie użyć parametru bezpośrednio?
Declan McKenna
1
Naprawdę niesamowita sugestia. Tak to zaimplementujemy w Swiftify :)
Crulex
13

Wiele osób sugeruje inoutparametr, ale tak naprawdę nie do tego zostały zaprojektowane. Poza tym nie pozwala na wywołanie funkcji letstałą, ani literałem tekstowym. Dlaczego po prostu nie dodasz wartości domyślnej do sygnatury funkcji?

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

Tylko pamiętaj, aby nie wywoływać getQuestionListz pustym ciągiem znaków na wypadek, gdybyś chciał użyć języka domyślnego, ale po prostu pomiń parametr:

let list = getQuestionList() // uses the default "NL" language
Tim Vermeulen
źródło
3
Ja też nie rozumiem, dlaczego wszyscy podążyli roztworze InOut gdy PO nie było nawet przy użyciu, że na początku ...
Eric Aya
1
Zakładali, że var i inout robią to samo.
ryantxr
2

Szybki 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)

W niektórych przypadkach, jak doświadczyłem (przy bardziej złożonych konfiguracjach obejmujących tablice), tworzenie nowej właściwości w metodzie i jej mutowanie może nie zawsze działać. Nie wspominając o tym, że zaśmiecasz metodę zamiast po prostu dołączać ją inoutdo parametru i &jego argumentu, do czego została stworzona ta składnia.

bsod
źródło
1
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()

}

Abdul Rahman Khan
źródło
0

Myślę, że odpowiedzi @Harris i @garanda to najlepsze podejście.

W każdym razie w twoim przypadku nie potrzebujesz var, możesz zrobić:

public func getQuestionList(language: String) -> NSArray {
    if self.data.count > 0 {
        return self.data.objectForKey("questionList" + (language.isEmpty ? "NL" : language)) as! NSArray
    }
    return NSArray()
}
Simone Pistecchia
źródło
0

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

Parametry wejściowe i wyjściowe

Parametry funkcji są domyślnie stałymi. Próba zmiany wartości parametru funkcji w treści tej funkcji powoduje błąd w czasie kompilacji. Oznacza to, że nie można przez pomyłkę zmienić wartości parametru. Jeśli chcesz, aby funkcja modyfikowała wartość parametru i chcesz, aby te zmiany były trwałe po zakończeniu wywołania funkcji, zamiast tego zdefiniuj ten parametr jako parametr wejściowy.

Piszesz parametr in-out, umieszczając słowo kluczowe inout tuż przed typem parametru. Parametr in-out ma wartość, która jest przekazywana do funkcji, jest modyfikowana przez funkcję i przekazywana z powrotem z funkcji w celu zastąpienia oryginalnej wartości. Aby uzyskać szczegółowe omówienie zachowania parametrów wejściowych i wyjściowych i skojarzonych z nimi optymalizacji kompilatora, zobacz Parametry we-wy.

Możesz przekazać zmienną tylko jako argument dla parametru wejściowego-wyjściowego. Nie można przekazać stałej ani wartości literalnej jako argumentu, ponieważ stałych i literałów nie można modyfikować. Umieszczasz znak ampersand (&) bezpośrednio przed nazwą zmiennej, gdy przekazujesz ją jako argument do parametru wejściowego, aby wskazać, że może być modyfikowana przez funkcję.

UWAGA

Parametry wejściowe nie mogą mieć wartości domyślnych, a parametry zmienne nie mogą być oznaczone jako inout.

Oto przykład funkcji o nazwie swapTwoInts ( : :), która ma dwa wejściowe i wyjściowe parametry całkowite zwane a i b:

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

Funkcja swapTwoInts ( : :) po prostu zamienia wartość b na a, a wartość a na b. Funkcja wykonuje tę zamianę, przechowując wartość a w tymczasowej stałej o nazwie tymczasowa A, przypisując wartość b do a, a następnie przypisując tymczasową A do b.

Możesz wywołać funkcję swapTwoInts ( : :) z dwiema zmiennymi typu Int, aby zamienić ich wartości. Zauważ, że nazwy someInt i anotherInt są poprzedzone ampersandem, gdy są przekazywane do funkcji 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"

Powyższy przykład pokazuje, że oryginalne wartości someInt i anotherInt są modyfikowane przez swapTwoInts ( : :), mimo że zostały pierwotnie zdefiniowane poza funkcją.

UWAGA

Parametry wejściowe i wyjściowe nie są tym samym, co zwracanie wartości z funkcji. Powyższy przykład swapTwoInts nie definiuje zwracanego typu ani nie zwraca wartości, ale nadal modyfikuje wartości someInt i anotherInt. Parametry wejściowe i wyjściowe to alternatywny sposób na wywołanie przez funkcję efektu poza zakresem jej treści.

Mustafa Mohammed
źródło
0

Oto kolejny pomysł. Moim przypadkiem użycia było przekazanie tablicy ciągów, aby ją dołączyć, dla której tablica musi być przekazywana mutacyjnie. Ja też nie chciałem mieć w swojej klasie stanu. Więc stworzyłem klasę, która przechowuje tablicę i przekazuje ją. W zależności od twojego przypadku użycia może wydawać się głupie posiadanie klasy, która przechowuje tylko tę jedną zmienną.

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

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

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

Używam tylko metod appendi joinedna tablicy, więc łatwo było zmienić typ przy minimalnych innych zmianach w moim kodzie.

Przykładowe użycie:

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
}
webjprgm
źródło
Moja odpowiedź brzmi, jeśli chcesz, aby oryginalna wartość widziana przez dzwoniącego została zmodyfikowana. Jeśli chciałeś tylko móc lokalnie ponownie przypisać wartość, ale nie wpływać na dzwoniącego, inne odpowiedzi powyżej zajmują się tym.
webjprgm