下面的代码不会被编译,Swift编译器会显示错误:"Variable 'firstVar' used before being initialized"
。
var firstVar: Double
var secondVar = 2.0
if 1 > 0 {
firstVar = 2.0
}
print(firstVar)
同时Swift编译器(2.2)对以下代码没有问题,它打印"Hello, Stack Overflow"
。对于Swift 3.0,以下代码将按预期显示错误。
var firstVar: Double
var secondVar = 2.0
if 1 > 0 {
firstVar = 2.0
}
if secondVar > 1.0 && firstVar > 0 {
print("Hello, stackoverflow!")
}
你能解释一下,为什么第二个代码示例中if语句的第二个条件的计算结果为true,而编译器(Swift 2.2)在第一个代码示例中没有抱怨firstVar
被初始化确实如此。
答案 0 :(得分:1)
rhs
(&&
)的= firstVar
表达式自动包含在闭包中(此处:使用autoclosure
),这意味着firstVar
的评估延迟(延迟),这样你的例子将在使用Swift Playground的动态编译时“编译”。我可以推测,在使用Swift Playground时,只有在运行时时才会检查延迟评估的正确性的前提条件,而不是在编译时检查。
在实际项目中尝试相同时,编译器不需要限制自己进行快速动态编译,并且可以发现编译时错误:
“错误:变量'
...
'在初始化之前由闭包捕获”
即,上面不应该编译,但由于firstVar
语句正文中if
的条件初始化,实际上运行正常。请注意,1 > 0
为true
的事实不应影响这是编译时错误的事实,因为评估1 > 0
的状态是运行时决策
<强>详情
逻辑二进制中缀运算符'&&'
有一个右侧rhs
,它是懒惰实现的,@autoclosure
func &&(lhs: BooleanType, @autoclosure rhs: () -> BooleanType) -> Bool {
return lhs.boolValue ? rhs().boolValue : false
}
来自The Language Reference - Attributes:
<强>
autoclosure
强>此属性用于延迟表达式的评估 自动将该表达式包装在没有参数的闭包中。 将此属性应用于函数的参数声明或 不带参数且返回类型的方法类型 表达。具有
autoclosure
属性的声明意味着noescape
也是如此,除非传递了可选的属性参数escaping
。
我们可以通过以下示例更清楚地显示您的示例的行为:
var foo: Double
/* use autoclosure to capture the argument in a closure */
func bar(@autoclosure arg: () -> Double) {
print(arg())
}
/* or let the user explicitly supply the argument in a closure form */
func baz(arg: () -> Double) {
print(arg())
}
if true {
foo = 1.0
}
bar(foo) // 1.0, OK in Playground, error when in a project
baz() { foo } // 1.0, OK in Playground, error when in a project