在调用super.init之前,在表达式中使用初始化的属性会导致Swift错误。这与使用未初始化的属性不同,后者只会产生警告而不是错误。

4

这并不是关键问题,可以有解决方法,但仍然令人困惑。

请看下面的最简示例。我指的是已初始化的属性,在调用super.init()之前。为什么下面的语句会出现编译错误?使用表达式右侧的属性和左侧有什么特殊之处吗?

我查看了Swift语言指南,但没有找到任何相关信息。是Swift编译器出了问题,还是我在属性、self和init方面缺少了什么知识?或者在调用super.init之前,所有对"myProperty"的引用都应该出错?

(请注意,属性是常量(使用'let')还是其他类型,如Int,都无关紧要,情况都是一样的。)

class MyClass : NSObject {
    var myProperty: Bool

    override init() {
        myProperty = true

        if myProperty { /* this is ok */ }
        if myProperty || true { /* this is ok */ }
        if true || myProperty  { /* this is NOT ok! ('self used before super.init') - WHY? */ }

        super.init()

        if true || myProperty  { /* now this is ok */ }
    }
}
2个回答

4
这是因为||被声明为副作用的结果。
func ||<T : BooleanType>(lhs: T, rhs: @autoclosure () -> Bool) -> Bool

因此,编译器会处理

true || myProperty

as

true || { self.myProperty }()

原因是 || 运算符的“短路行为”:如果第一个操作数为真,则根本不需要评估第二个操作数。
(旁注:我假设在编译/优化过程的后期,这个过程会被简化,因此最终代码实际上不会创建和调用闭包。)
在闭包内访问 self 导致了错误消息。你将得到同样的错误。
override init() {
    myProperty = true
    let a = { self }() // ERROR: self used before super.init
    super.init()
    let b = { self }() // OK after super.init
}

哇,谢谢,这解释了不对称性以及为什么 RHS 不同于其他非表达式用法,在引入“self”引用时。惊人的是,这个“干净简单”的语言下面有多少复杂性!很棒的答案。 - Dennis M.

0

我认为这是预期的行为,也是两阶段初始化的一部分。

这是以下规则的结果:

  • 在调用super.init之前必须初始化所有属性,即在声明的同一行或在init中在super.init之前进行初始化
  • 在第一阶段初始化完成之前,初始化程序不得调用任何实例方法,读取任何实例属性的值或将self引用为值

1
按照这个逻辑,前两个“if”语句也应该出错,因为它们在第一阶段完成之前引用了实例属性的值。因此,问题仍然是未决的,只是反过来:这是Swift的一个bug吗,导致前两个“if”被接受? - Dennis M.
如果是这样,我会期望你的另外两个语句也失败。 - MirekE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接