请考虑以下代码:
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"
封闭似乎创造了成功的副本,并没有改变原作。为什么会这样?我假设闭包会指向原文,因为我们传递的是inout
变量。
答案 0 :(得分:5)
有意义的是,这不会更新您的success
变量,因为您的inout
参数是foo
的参数,而不是闭包本身。如果将inout
参数设为闭包的参数,则会得到所需的行为:
var success = false
let closure = { (inout flag: Bool) -> () in
flag = true
print(flag)
}
closure(&success) //prints "true"
print(success) //prints "true"
只要您将inout
参数保留为闭包的参数,此模式也适用于该函数:
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"
如果使用引用类型,也会获得所需的行为:
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"
答案 1 :(得分:5)
这似乎由Swift Evolution proposal 0035涵盖,并被视为错误。
该文档将函数的inout
参数称为" 卷影副本,当被调用者返回"时,该参数将被写回参数。这似乎意味着在success
的执行上下文中实际上存在一个名为foo()
的临时变量。然后,只有当success
返回时,该temp的值才会被放入外部foo()
。
因为在你的foo()
中,当foo()
返回时,闭包没有运行," shadow copy"没有改变。外success
保留其值。
重要的一点是,关闭已经捕获了卷影副本 ,而不是您期望的外部success
。因此,当闭包最终运行时,该变量的值确实会发生变化,但它不再与原始外部success
建立任何连接。
该提案使用此代码段演示:
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