这非常类似于返回 Self 的协议函数 https://stackoverflow.com/questions/25645090/protocol-func-returning-self,但足够不同,可能值得单独回答。这里有两个问题。
第一个问题是为什么你需要final
。正如上面的问题一样,问题在于您做出的承诺编译器无法证明您会遵守。
考虑以下子类:
class LocalFireman: Fireman {
let zipcode: String
init(zipcode: String) { self.zipcode = zipcode }
}
什么应该LocalFireman.shared
返回?它无法返回消防员。你说它必须返回 Self(即 LocalFireman)。并且它不能返回LocalFireman
,因为它没有用于初始化的邮政编码。那么现在怎么办?
Swift 不会让你陷入这个困境,因为它要求你要么确定特定的类型shared
(即它永远是Fireman
,即使你在子类上调用它),或者你需要承诺不会有子类,或者你需要要求所有子类都实现init
:
required init() {}
好吧,但你已经做到了这一点。你标记了final
,它仍然抱怨。现在您遇到了编译器限制。整个要点Self
是协方差;它是调用时的动态类型,而不是上下文中的静态类型 https://forums.swift.org/t/pitch-adding-a-self-type-name-shortcut-for-static-member-access/2056。这不仅仅是表达“我的类型”的便捷方式,而且这是一种选择(尽管我认为这是可以改变的)。它意味着“我的协变类型”,即使您处于不可能有任何子类型的情况。
综上所述,鉴于private
init,我很困惑你为什么说标记它final
是“违背我的意愿”。我摔倒init
是私有的,无论如何都不能子类化,所以看起来你想要一个最终类,如果是这样,那么只需将类名放在它所在的位置即可。Self
不是为了这个问题(今天)。
这就留下了一个悬而未决的问题:为什么你不能使用必需的 init 来做到这一点。Self
作为“类的类型”和Self
因为“符合协议的事物类型”被视为同一事物。所以你不能只在课堂上考虑这个问题;任何东西都可以“继承”(遵守)协议。所以Self
可以潜在地引用一个结构。结构可以是任意大小。因此允许存储的属性为类型Self
产生内存布局问题。 (我也不认为 Swift 承诺类将始终作为指针实现,因此这可能会导致类出现同样的问题,至少在原则上是这样。)
您可以返回类型的值Self
来自函数,但你不能将其放入存储属性中(静态和非静态属性都是如此),并且 Swift 也不允许它们用于计算属性(我认为这只是为了一致性)。因此,以下内容是允许的(实际上很有用):
class Fireman {
required init() {}
static func make() -> Self { return Self() }
}
这就是Self
is for.