gpt4 book ai didi

swift - 无法从存储的属性初始化程序引用协变 'Self' 类型

转载 作者:行者123 更新时间:2023-12-03 19:42:49 26 4
gpt4 key购买 nike

在下面的代码中,我不明白为什么在使用 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 )。所以只是为了避免进一步的子类化,尽管我违背我的意愿宣布了类 final

最佳答案

这与 Protocol func returning Self 非常相似,但足够不同,可能值得单独回答。这里有两个问题。

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

考虑以下子类:

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是协方差; it's the dynamic type at the point of calling, not the static type in context .这不仅仅是说“我的类型”的方便方式,而且这是一种选择(尽管我认为这可能会改变)。即使您处于不能有任何子类型的情况,它也意味着“我的协变类型”。

综上所述,鉴于 private init,我很困惑你为什么说标记它 final是“违背我的意愿”。如果全部 init是私有(private)的,无论如何它都不能被子类化,所以看起来你想要一个最终类,如果是这样,那么只需将类名放在它所在的位置。 Self不是为了那个问题(今天)。

这留下了一个问题,即为什么您不能使用所需的 init 来执行此操作。 Self作为“类的类型”和 Self作为“符合协议(protocol)的事物类型”被视为同一事物。所以你不能只在类里面考虑这个;任何东西都可以“继承”(遵守)协议(protocol)。所以 Self可以潜在地引用一个结构。结构可以是任意大小。因此允许存储的属性为 Self 类型造成内存布局问题。 (我不认为 Swift promise 类将始终作为指针实现,因此这可能会导致类出现同样的问题,至少在原则上是这样。)

您可以返回 Self 类型的值来自一个函数,但你不能把一个放在存储属性中(静态和非静态属性都是如此),而且 Swift 也不允许它们用于计算属性(我假设这只是为了保持一致性)。所以以下是允许的(实际上很有用):
class Fireman {
required init() {}
static func make() -> Self { return Self() }
}

这就是 Self是为了。

关于swift - 无法从存储的属性初始化程序引用协变 'Self' 类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60643745/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com