2016-04-25 15 views
6

Rozważmy następujący kod:Swift przechwytywania zamknięcie i inout zmiennych

func foo(inout success: Bool) -> (()->()) { 
    return { _ in 
     success = true 
     print (success) 
    } 
} 

var success = false 
let closure = foo(&success) 

closure()   //prints "true" 
print(success)  //prints "false" 

Zamknięcie wydaje się być tworzenie kopii sukcesu i nie zmienia oryginalnego. Dlaczego to się dzieje? Przyjąłem, że zamknięcie wskaże oryginał, ponieważ przekazujemy zmienną inout.

Odpowiedz

3

To ma sens, aby nie zaktualizować zmienną success, ponieważ parametr inout jest parametrem foo, a nie samym zamknięciem. Można uzyskać pożądane zachowanie Jeśli się parametr inout parametr zamknięcia:

var success = false 
let closure = { (inout flag: Bool) ->() in 
    flag = true 
    print(flag) 
} 

closure(&success) //prints "true" 
print(success)  //prints "true" 

Wzór ten również działa z funkcją też, tak długo, jak zachować parametr inout parametr zamknięcia:

func foo() -> ((inout Bool)->()) { 
    return { flag in 
     flag = true 
     print (flag) 
    } 
} 

var success = false 
let closure = foo() 

closure(&success) //prints "true" 
print(success)  //prints "true" 

również uzyskać pożądane zachowanie, jeśli używasz typ referencyjny:

class BooleanClass: CustomStringConvertible { 
    var value: Bool 

    init(value: Bool) { 
     self.value = value 
    } 

    var description: String { return "\(value)" } 
} 

func foo(flag: BooleanClass) -> (()->()) { 
    return { 
     flag.value = true 
     print (flag) 
    } 
} 

let success = BooleanClass(value: false) 
let closure = foo(success) 

closure()   //prints "true" 
print(success)  //prints "true" 
4

to wydaje się być objęta Swift Evolution proposal 0035 i jest uważany za błąd.

Dokument ten odnosi się do parametru do funkcji "a shadow copy, który jest zapisywany z powrotem do argumentu, gdy odwołanie zwraca". Wydaje się to oznaczać, że istnieje w istocie zmienna tymczasowa o nazwie success w kontekście wykonywania foo(). Wartość tej temperatury jest następnie umieszczana w zewnętrznym success tylko po zwrocie foo().

Ponieważ w twoim foo() zamknięcie nie zostało uruchomione po powrocie foo(), wartość "kopii w tle" nie uległa zmianie. Zewnętrzna success zachowuje swoją wartość.

Ważne jest to, że zamknięcie zdobył kopię cień, a nie zewnętrzna success jak można się spodziewać. Tak więc, gdy zamknięcie zostanie ostatecznie uruchomione, wartość tej zmiennej się zmieni, ale nie ma już żadnego połączenia z oryginalnym zewnętrznym success.

Wniosek wykorzystuje ten fragment wykazać:

func captureAndEscape(inout x: Int) ->() -> Void { 
    let closure = { x += 1 } 
    closure() 
    return closure 
} 

var x = 22 
let closure = captureAndEscape(&x) 
print(x) // => 23 
closure() 
print("still \(x)") // => still 23 
+0

Dlaczego kopii w tle? Czy to jest płytka kopia? –

+0

"Cień" w tym sensie, że jest ukryty. –

Powiązane problemy