无法从存储的 属性 初始值设定项引用协变 'Self' 类型

Covariant 'Self' type cannot be referenced from a stored property initializer

在下面的代码中,我不明白为什么在使用 Self() 时会出现上述错误?如果我将代码替换为 Fireman() .

,代码就可以正常工作
final class Fireman {

    var numOfServices = 0

    private init(){}
    static var shared = Self() <-------- Here !!!

    func extinguishFire() {
        self.numOfServices += 1
        print("Spraying water...\(self.numOfServices)")
    }
}

另外,我必须标记 class final 的原因是,如果没有它,错误消息是我必须包含一个 required 初始化程序(当我这样做时我再次收到错误消息,因为我的初始化程序是 private)。所以只是为了避免进一步 subclassing ,尽管违背我的意愿我宣布了 class final

这与 Protocol func returning Self 非常相似,但差异很大,可能值得单独回答。这里有两个问题。

第一个问题是为什么需要 final。与上述问题一样,问题在于您做出了编译器无法证明您会遵守的承诺。

考虑以下子class:

class LocalFireman: Fireman {
    let zipcode: String
    init(zipcode: String) { self.zipcode = zipcode }
}

LocalFireman.sharedreturn应该怎么办?它不能 return 消防员。你说它必须 return 自己(即 LocalFireman)。而且它不能 return a LocalFireman,因为它没有用于初始化的邮政编码。那么现在呢?

Swift 不会要求您确定 shared 的特定类型(即它始终是 Fireman,即使您在 subclass 上调用它),或者你需要保证不会有 subclasses,或者你需要要求所有 subclasses 实现 init

required init() {}

好的,但你已经说到这里了。你标记它 final,它仍然抱怨。现在您遇到了编译器限制。 Self 的重点是协方差; it's the dynamic type at the point of calling, not the static type in context。这不仅是 "my type" 的便捷表达方式,而且还是一种选择(尽管我认为这是可以改变的)。这意味着 "my covariant type" 即使您处于不能有任何子类型的情况下。

综上所述,鉴于 private 初始化,我很困惑为什么你说标记它 final 是 "against my will." 如果所有 init 都是私有的,这可以无论如何都不会被 subclassed,所以看起来你想要一个最终的 class,如果是这样,那么只需将 class 名称放在它所在的位置。 Self 不适用于那个问题(今天)。

这留下了一个悬而未决的问题,即为什么您不能使用必需的 init 来执行此操作。 Self 作为 "type of class" 和 Self 作为 "type of thing conforming to a protocol" 被视为同一事物。所以你不能只在 class 的情况下考虑这个;任何东西都可以"inherit"(符合)协议。所以 Self 可以潜在地引用一个结构。结构可以是任何大小。因此,允许存储的 属性 类型为 Self 会产生内存布局问题。 (我也不认为 Swift 承诺 classes 将始终作为指针实现,因此这可能会导致 classes 出现同样的问题,至少在原则上是这样。)

您可以 return 来自函数的类型 Self 的值,但您不能将其放入存储的 属性 中(这对于静态和非静态属性),并且 Swift 也不允许它们用于计算属性(我假设这只是为了保持一致性)。所以以下是允许的(实际上是有用的):

class Fireman {
    required init() {}
    static func make() -> Self { return Self() }
}

这就是 Self 的目的。