调度到 Swift 协议扩展
Dispatching to Swift protocol extension
为什么以下代码在#2 处打印“BaseP”?
protocol BaseP { func foo() }
extension BaseP { func foo() { print("BaseP") } }
protocol SubP: BaseP {}
extension SubP { func foo() { print("SubP") } }
class C: SubP {}
let subP1: SubP = C()
subP1.foo() // #1 prints "SubP", fine.
class BaseC: BaseP {}
class SubC: BaseC, SubP {}
let subP2: SubP = SubC()
subP2.foo() // #2 prints "BaseP". why?
在这两种情况下,我们都在静态类型为 SubP
的引用上调用 foo()
,
引用具有符合 SubP
的 class 动态类型的对象。
即使它是静态调度,我认为它仍然应该调用 SubP.foo()
。
为什么在 #2 调用基本协议实现?
此外,为什么从 BaseC
继承会有所不同
(如果在 class SubC
行中我删除了 BaseC
或将其替换为 BaseP
,
然后它突然打印出 "SubP")?
当你调用subP1.foo()
或subP2.foo()
时,你调用的是BaseP
中满足协议要求foo
的foo
。 (即 见证 BaseP.foo
的方法)。 这样的证人只能有一个。
另一个重要的是foo
要求不在SubP
中,而是在BaseP
中。 SubP
的唯一要求是符合者也必须符合 BaseP
。
在subP1
的情况下,C
直接符合SubP
。要解决 SubP
的唯一要求,C
也必须符合 BaseP
。现在编译器需要确定哪个方法可以见证 foo
。有两种方法可用,但是 SubP
扩展中的一种隐藏了 BaseP
扩展中的一种,因此选择 SubP
扩展中的一种作为见证,所以你看SubP
已打印。
在subP2
的情况下,foo
的witness在你让BaseC
符合BaseP
的时候就已经确定了。在这里,只有一个选择 - BaseC
扩展中的 foo
。当你后来让 SubC
符合 SubP
时,唯一剩下的要求就是 SubC
也应该符合 BaseP
。好吧,你说 SubC
继承自 BaseC
,所以没关系。编译器很高兴,BaseP
扩展中的 foo
最终成为见证人。
为什么以下代码在#2 处打印“BaseP”?
protocol BaseP { func foo() }
extension BaseP { func foo() { print("BaseP") } }
protocol SubP: BaseP {}
extension SubP { func foo() { print("SubP") } }
class C: SubP {}
let subP1: SubP = C()
subP1.foo() // #1 prints "SubP", fine.
class BaseC: BaseP {}
class SubC: BaseC, SubP {}
let subP2: SubP = SubC()
subP2.foo() // #2 prints "BaseP". why?
在这两种情况下,我们都在静态类型为 SubP
的引用上调用 foo()
,
引用具有符合 SubP
的 class 动态类型的对象。
即使它是静态调度,我认为它仍然应该调用 SubP.foo()
。
为什么在 #2 调用基本协议实现?
此外,为什么从 BaseC
继承会有所不同
(如果在 class SubC
行中我删除了 BaseC
或将其替换为 BaseP
,
然后它突然打印出 "SubP")?
当你调用subP1.foo()
或subP2.foo()
时,你调用的是BaseP
中满足协议要求foo
的foo
。 (即 见证 BaseP.foo
的方法)。 这样的证人只能有一个。
另一个重要的是foo
要求不在SubP
中,而是在BaseP
中。 SubP
的唯一要求是符合者也必须符合 BaseP
。
在subP1
的情况下,C
直接符合SubP
。要解决 SubP
的唯一要求,C
也必须符合 BaseP
。现在编译器需要确定哪个方法可以见证 foo
。有两种方法可用,但是 SubP
扩展中的一种隐藏了 BaseP
扩展中的一种,因此选择 SubP
扩展中的一种作为见证,所以你看SubP
已打印。
在subP2
的情况下,foo
的witness在你让BaseC
符合BaseP
的时候就已经确定了。在这里,只有一个选择 - BaseC
扩展中的 foo
。当你后来让 SubC
符合 SubP
时,唯一剩下的要求就是 SubC
也应该符合 BaseP
。好吧,你说 SubC
继承自 BaseC
,所以没关系。编译器很高兴,BaseP
扩展中的 foo
最终成为见证人。