闭包如何捕获值类型?

How closure captures value type?

请看下面这个简单的例子:

var cl: (() -> ())! 
func foo() { 
    var x = 20
    cl = { 
      print(x)
    }

}
foo()
cl() // prints 20

由于 x 是一个 Int,它是一个值类型,并且值类型“存在”在堆栈中,一旦 foo returns x应该消失。按照上面提到的推理,当 cl 被调用时 x 不应该存在,但它仍然打印 20。有人可以解释闭包如何在这种情况下捕获 x 并将其保存在内存中。
请注意,在这种情况下,我没有使用捕获列表捕获 x。在捕获列表的情况下,这是显而易见的,因为使用捕获列表捕获值类型只是复制捕获的值。

Can somebody explain how closure captures x in this case and keeps it in memory.

并没有真正的“如何”。这就是闭包 。它 确实 捕获 x 并将其保存在内存中。基本上,当本地引用超出范围时,您的 x 不会消失,因为闭包已捕获它并继续存在;因此 xfoo 有 运行 之后仍然存在,在属于这个闭包的不可见的“闭包捕获”space 中关闭,只要闭包本身存在。

闭包之所以能成为闭包,正是因为闭包能够做到这一点。

这个能力的一个特征是你的例子没有得到的是捕获的引用仍然是可写(因为你说的是​​var)。例如:

var cl: (() -> ())!
func foo() {
    var x = 20
    cl = {
      print(x)
      x += 1
    }

}
foo()
cl() // prints 20
cl() // prints 21

因此,我们能够在闭包捕获世界中保持状态关闭。

另一件需要注意的事情(我想你知道这一点)是如果这 不是 是一个超出范围的自动变量,写入它会影响 original — 引用是直接的。因此:

var cl: (() -> ())!
var x = 20
func foo() {
    cl = {
      print(x)
      x += 1
    }

}
foo()
cl() // prints 20
cl() // prints 21
print(x) // 22