在 Swift 中,闭包不仅可以作为函数的简洁表达方式,还能捕获和存储其所在上下文中的常量和变量。捕获的变量会随着闭包的生命周期延续,即使这些变量已经超出了原作用域,它们仍然可以在闭包中被访问和修改。这种行为被称为闭包捕获,是闭包的核心特性之一。
//变量值捕获
func makeIncrementer() -> () -> Int { var total = 0 // 这是外部变量 let incrementer: () -> Int = { total += 1 // 闭包捕获了外部变量 total return total } return incrementer } let increment = makeIncrementer() print(increment()) // 输出 1 print(increment()) // 输出 2
// 在这个例子中,total
变量是在makeIncrementer
函数内定义的,它对incrementer
闭包来说是“外部”的。但由于闭包捕获了这个外部变量,total
可以在闭包内部被修改和访问。
//引用类型捕获
class ReferenceType { var value: Int = 0 } func referenceClosure() -> () -> Int { let ref = ReferenceType()//函数内声明了一个局部变量 let closure: () -> Int = { ref.value += 1 //闭包内修改外界变量 return ref.value } return closure } let closureRef = referenceClosure() print(closureRef()) // 输出 1 print(closureRef()) // 输出 2
//closure
是一个闭包,它捕获了ReferenceType
的实例ref
。这个ref
是referenceClosure
函数中的局部变量,但由于被闭包捕获,在referenceClosure
返回后,ref
仍然存在于闭包中,并且它的value
属性可以继续被修改。
为什么闭包要捕获外部变量?
闭包需要捕获外部变量,主要是为了保持它们的状态,即使闭包所在的作用域已经结束。
- 如果一个变量定义在函数内部,但闭包捕获了它,该变量就不会随着函数的结束而销毁。闭包可以长期持有该变量的引用,并在后续调用时继续使用它。
- 闭包内部变量:是在闭包的代码块内部定义并使用的变量,通常只能在闭包内访问。
- 外部变量:是在闭包所在的作用域(函数或其他代码块)中定义,但被闭包引用的变量。由于它们是在闭包外部定义的,所以称为“外部变量”。