考虑以下代码:
class Foo {
var a: Int
var b: Int
init(a: Int, b: String?) throws {
self.a = a
guard self.a > 0 else {
throw "Too little a!"
}
self.b = self.a
}
}
extension String: Error {}
非常不敏感,但关键是它编译得很好。 现在用以下内容替换后卫:
guard b == nil || self.a > 0 else {
我们没有收到编译错误!
错误:' self'在所有成员初始化之前由关闭捕获
我不会在任何地方看到关闭。如果编译器是复合表达式,编译器是否会将guard
条件转换为闭包,从而引入错误(如果 是一个闭包,这将是正确的)?
错误或功能?
这是使用Swift 3.0.2。
答案 0 :(得分:2)
正如马丁in this Q&A所解释的那样,问题是||
operator是用@autoclosure
秒参数实现的,以便进行短路评估(右手表达式)只有在左手表达式求值为false
时才需要进行评估。
因此在表达式中
b == nil || self.a > 0
self.a > 0
隐式包含在() -> Bool
闭包中。这是有问题的,因为它需要捕获self
,以便在应用闭包时可以访问a
。
但是,在初始化程序中,Swift严格限制了self
在完全初始化之前可以执行的操作。其中一个限制是无法通过闭包捕获 - 这就是您遇到编译器错误的原因。
尽管如此,在{ self.a > 0 }
完全初始化之前,self
关闭a
没有任何问题,因为所有关闭操作都是访问它self.a
,它已经被初始化了。因此,这实际上只是一个边缘情况(there's an open bug report),我希望将来会在该语言的未来版本中进行平滑。
在此之前,Martin in this Q&A所示的一个解决方案是使用临时局部变量来创建self
值的副本,从而避免在class Foo {
var a: Int
var b: Int
init(a: Int, b: String?) throws {
// some computation meaning that a != self.a
self.a = a * 42
// temporary local variable to be captured by the @autoclosure.
let _a = self.a
guard b == nil || _a > 0 else {
throw "Too little a!"
}
self.b = self.a
}
}
extension String: Error {}
中捕获self.a != a
封闭:
a
显然,这假定为self.a
,否则您只能在guard
条件中引用{{1}}而不是{{1}}。