Szybka zmiana parametru metody?

123

Jak mogę sobie poradzić z tym błędem bez tworzenia dodatkowej zmiennej?

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

Nie chcę tworzyć dodatkowej zmiennej tylko po to, aby przechowywać wartość x. Czy w ogóle można robić to, co chcę?

Gabriel
źródło
3
Zobacz zaktualizowane odpowiedzi poniżej. Swift 3 wycofał zaakceptowaną odpowiedź.
achi

Odpowiedzi:

193

Jak stwierdzono w innych odpowiedziach, od wersji Swift 3 umieszczanie zmiennej przed zmienną została wycofana. Chociaż nie podano w innych odpowiedziach, jest możliwość zadeklarowania inoutparametru. Pomyśl: podając wskaźnik.

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

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

Może to być szczególnie przydatne w przypadku rekurencji.

inoutWytyczne dotyczące deklaracji Apple można znaleźć tutaj .

achi
źródło
2
Dziękuję Ci bardzo!!!! Utknąłem tutaj na pytaniu rekurencyjnym. Uratowałeś mi życie.
JW.ZG
2
Należy używać tego ostrożnie, ponieważ modyfikuje to zmienne poza zakresem funkcji. Idealnie byłoby, gdybyś chciał jawnie zwrócić wartość zmienioną wewnątrz funkcji.
Chris Gunawardena,
2
inoutsłowo kluczowe powinno być umieszczone pomiędzy nazwą parametru a typem parametru w następujący sposób: func reduceToZero(x: inout Int) w obecnej wersji Swift 3.
Agustí Sánchez
Tyle, że to nie wydaje się działać w przypadku domknięć, ponieważ domknięcia najwyraźniej przechwytują tylko parametry inout według wartości (przynajmniej taki jest komunikat o błędzie, który podaje mi Xcode). W tym przypadku używam rozwiązania @GeRyCh.
wcochran
Dziękuję Ci. Na razie to działało, ale przypomina używanie wskaźników w C. Czy to przetrwa inną wersję Swift?
Krishna Vedula
45

Parametry „var” są przestarzałe i zostaną usunięte w języku Swift 3. Dlatego przypisanie do nowego parametru wydaje się teraz najlepszym sposobem:

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

jak wspomniano tutaj: parametry „var” są przestarzałe i zostaną usunięte w języku Swift 3

GeRyCh
źródło
1
W tym przypadku, czy faktycznie kopiuje xw nowym var x? A może Swift robi coś bardziej wydajnego niż to?
Genki,
3
To działa i właśnie to robię, ale wydaje się bardzo niezręczne.
wcochran
1
@Gomfucius Ani słowa o tym w przewodniku do Swift 3.1. W tym przypadku ( xwpisuje się w rejestrze) nie ma praktycznie żadnych kosztów. Jeśli xjest to tablica, struktura lub obiekt, który jest zmutowany, to prawie na pewno trzeba wykonać kopię (chyba że optymalizator może przeanalizować ją wewnętrznie i utworzyć alias).
wcochran,
1
@wcochran To fajna sztuczka, ale tak naprawdę nie dzieje się nic specjalnego. To po prostu przesłanianie parametru wejściowego lokalną kopią zmiennej. W sytuacji PO jest lepszym zamiennikiem varargumentów niż użycie, inoutktóre może mieć niezamierzone skutki uboczne, zwł. gdyby var był wskaźnikiem.
Echelon
45

Dla Swift 1 i 2 (dla Swift 3 patrz odpowiedź achi przy użyciu parametru inout): Argument funkcji w Swift jest letdomyślny, więc zmień go na, varjeśli chcesz zmienić wartość, tj.

func reduceToZero(var x:Int) -> Int {
    while (x != 0) {
        x = x-1     
    }
    return x
}
LML
źródło
2
Dlaczego ta odpowiedź została przegłosowana jak diabli? Druga odpowiedź została umieszczona przed tą i zawiera więcej informacji niż ta.
Cristik
16
/! \ Użycie var utworzy kopię zmiennej przekazanej w parametrach. Więc modyfikacja nie zmieni oryginalnej wartości. Również varw parametrach jest bardzo prawdopodobne, że znikną w nowszych wersjach Swift na github.com/apple/swift-evolution/blob/master/propeals/ ...
Matthieu Riegler
17
słowo kluczowe var w parametrze metody zostanie wycofane w wersji Swift 3.
Boon
4
Myślę, że w przypadku Swift 3 nie będziemy już w stanie tego zrobić. Będziemy musieli utworzyć zmienną kopię tablicy i zwrócić tę zmodyfikowaną tablicę.
C0D3
Ta odpowiedź jest poprawna: stackoverflow.com/questions/24077880/…
achi
14

Odpowiedź Swift3 za przekazanie wskaźnika tablicy mutable.

Funkcjonować:

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

Wezwanie do funkcji:

var a = Array<Int>()
foo(array:&a)
joshd
źródło
Szczerze mówiąc, nie jestem pewien, czy to prawda, ponieważ grunt Swifta ciągle się zmienia. Pomyślałem, że to lepsze niż robienie var array = array wewnątrz funkcji, ponieważ tworzy kopię (i faktycznie nie wpływa na oryginalną strukturę tablicy)? Czy jest lepsze podejście projektowe do wspomnianego wcześniej podejścia var, a następnie zwrócenie nowej zmutowanej tablicy?
joshd
7

W Swift po prostu dodajesz varsłowo kluczowe przed nazwą zmiennej w deklaracji funkcji:

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

Zapoznaj się z podrozdziałem „Parametry stałe i zmienne” w rozdziale „Funkcje” książki Swift (strona 210 w iBooku w obecnym stanie).

DK_
źródło
7
Parametry „var” są przestarzałe i zostaną usunięte w Swift 3
Regis St-Gelais
1
Nie dotyczy wersji Swift 4 i nowszych.
ilkayaktas
0

Są przypadki, w których nie chcieliśmy używać inout

Możemy użyć czegoś takiego, jeśli chcesz, aby te zmiany / zakres były tylko wewnątrz funkcji:

func manipulateData(a: Int) -> Int {
    var a = a
    // ...
}
dheeru
źródło
0

Rozwiązanie wykorzystujące Swift5 z programowaniem funkcjonalnym ...

func reduceToZeroFP(x:Int) -> Int {
    x == 0 ? x : reduceToZeroFP(x: x - 1)
}
Jules Burt
źródło