如果一个类实现了声明了可失败初始化器的协议,为什么它不需要提供一个可失败初始化器?

5

我正在尝试理解以下这个“人为的”示例:

protocol MyProtocol {
  init?(string: String)
}

class MyObject: MyProtocol {
  let s: String
  required init(string: String) {
    self.s = string
  }
}

let o = MyObject(string: "test")
print(o.s)

MyProtocol声明了一个可失败的初始化器MyObject符合MyProtocol,示例代码编译并执行没有问题。

我的问题是:为什么MyObject不必提供一个可失败的初始化器(根据MyProtocol)?


2
可失败的初始化器仍然是一个在理想情况下返回MyObject的初始化器。它被拥有相同签名的不可失败的初始化器所取代。你仍然必须提供具有相同签名的初始化器才能使代码编译通过。我猜这是一个不能失败的可失败初始化器。在某种程度上是这样。 - Fogmeister
1
也许是因为可选项是可选的?哈哈,但更严肃的是,一个始终为.Some的初始化对象将满足您的协议。 - NSGangster
1个回答

6

这是因为同样的原因,它可以编译通过:

class A {
    init?(s:String) {}
    init() {}
}
class B : A {
    override init(s:String) {super.init()}
}

init 可以覆盖(即替换)init?

参见文档(当某个语言特性已经被清晰地记录在文档中时,询问“为什么”似乎有些无意义:这只是一种关于语言的事实):

一个可失败的初始化要求可以由符合类型上的可失败或不可失败的初始化器满足。

(正如在问题和答案的评论中指出的那样,如果考虑到 init? 从未失败和具有相同签名的 init 之间的区别,这就是完全有道理的——即,没有任何有效区别。换句话说:你可以告诉我我可能会失败,但你无法告诉我我必须失败。)


当您拥有B的实例时,*init?()的实现是存在的。但在我的情况下,MyObject没有为MyProtocol的可失败初始化器提供实现。 - RobertJoseph
3
之所以可失败初始化方法需要返回一个nil非nil的对象,是因为一个不可失败的初始化方法总是返回一个非nil的对象,这符合了该协议并且也很合理。 - NSGangster
1
@NSGangster 说得非常好。@RobertJoseph,这里有另外一种看待它的方式:想象一下你实现了 init?,但事实上,你的实现从来没有返回过 nil。显然,那样就能够满足要求。而实现 init 就跟那个一样。 - matt
1
+1 如果在文档中找到了。对于那些正在寻找的人,它位于名为“可失败初始化器要求”的部分下面。 - NSGangster

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