闭包如何捕获先前调用的值?

时间:2016-06-15 14:59:01

标签: swift closures

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

不是A' A行'我们每次拨打counter1()时都会打电话?这意味着每次都应该调用var n = 0 ......

为什么计数器会返回不同的值?他们不应该总是回来' 1' ?

2 个答案:

答案 0 :(得分:1)

显然,每次调用counter1时都不会调用A行

事件的顺序是:

  • makeCounter被调用,它声明并初始化n(行A),定义adder,并在包含的上下文中返回adder n已经定义并初始化为1

  • 刚刚返回的此函数已分配给counter1。因为A行不是该函数的一部分(adder / counter1),所以在调用该函数时它不会被执行。

  • counter1的每次调用都是在同一个上下文中执行的,这就是n在调用中保留其值的原因:它们都访问相同的n

答案 1 :(得分:1)

您曾致电makeCounter()一次。这会创建新的闭包,并将其分配给counter1。这个闭包关闭了可变var n,只要存在闭包,它就会被捕获。

调用counter1()将执行它,但它会保留相同的捕获n,并对其进行变更。这个特殊的“加法器”将始终捕获相同的n,只要它存在..

要获得您建议的行为,您需要创建新的闭包,以捕获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

现在,counter1counter2都有自己独立的n实例。