问题
typealias IntMaker = (Void)->Int
func makeCounter() ->IntMaker{
var n = 0 // Line A
func adder()->Integer{
n = n + 1
return n
}
return adder
}
let counter1 = makeCounter()
counter1() // returns 1
counter1() // returns 2
counter1() // returns 3
Isn't 'Line A' called each time we call counter1()
? meaning that var n = 0
should be called every time...
Why is that the counter returns different values? Shouldn't they always be returning '1' ?
回答1:
You've called makeCounter()
once. That creates your new closure, and assigns it to counter1
. This closure closes over the mutable var n
, and will remain captured as long as this closure exists.
Calling counter1()
will execute it, but it retains the same captured n
, and mutates it. This particular "adder" will ALWAYS capture this same n
, so long as it exists..
To get the behavior you're suggesting, you need to make new closures which capture new instances of n
:
let counter1 = makeCounter()
counter1() // returns 1
counter1() // returns 2
counter1() // returns 3
var counter2 = makeCounter()
counter2() // returns 1
counter2 = makeCounter()
counter2() // returns 1
counter2 = makeCounter()
counter2() // returns 1
Now both counter1
and counter2
each have their own separate instances of n
.
回答2:
Obviously, Line A isn't being called each time counter1
is called.
The sequence of events is:
makeCounter
is called, which declares and initializesn
(Line A), definesadder
, and returnsadder
in a context that includesn
already having been defined and initialized to 1.It is this function that was just returned that is assigned to
counter1
. Because the Line A is not part of that function (adder
/counter1
), it does not get executed when that function is called.Each call to
counter1
is executed in that same context, which is whyn
retains its value across calls: they are all accessing the samen
.
来源:https://stackoverflow.com/questions/37839020/how-do-closures-capture-values-from-previous-calls