问题描述
请考虑以下 Swift 5 代码:
protocol P: class {
func call_foo()
func foo()
func call_bar()
func bar()
}
extension P {
func call_foo() { foo() }
func foo() { print("P.foo") }
func call_bar() { bar() }
func bar() { print("P.bar") }
}
class C1: P {
func foo() { print("C1.foo") }
}
class C2: C1 {
func bar() { print("C2.bar") }
}
let c = C2()
c.call_foo() // C1.foo
c.foo() // C1.foo
c.call_bar() // P.bar
c.bar() // C2.bar
如果 foo()
中的 P.call_foo()
调用被动态分派到 C1.foo()
,那么为什么 bar()
中的 P.call_bar()
调用没有被动态分派到 {{ 1}}?
唯一的区别是C2.bar()
在符合foo()
的类中被直接覆盖,而P
只在子类中被覆盖。为什么会有所不同?
鉴于 bar()
是一项协议要求,对它的所有调用不应该总是动态调度吗?
解决方法
在您的扩展程序的上下文中:
extension P {
func call_foo() { foo() }
func foo() { print("P.foo") }
func call_bar() { bar() }
func bar() { print("P.bar") }
}
C2
不存在,P
是一个协议,方法是静态派发的,虽然bar()
是P
的一个要求,但它不是由{ {1}} 符合 C1
所以:
P
这是正常的,有趣的是你有:
let c1: some P = C1()
c1.call_foo() // C1.foo
c1.foo() // C1.foo
c1.call_bar() // P.bar
c1.bar() // P.bar
这意味着如果您只有对 let someP: some P = C2()
someP.call_foo() // C1.foo
someP.foo() // C1.foo
someP.call_bar() // P.bar
someP.bar() // P.bar
的引用,则 some P
的子类 C2
的行为与它的超类完全一样:C1
调用 call_bar()
因为 { {1}} 未实现 P.bar()
现在让我们看看如果您在 C1
中实现 bar()
会发生什么:
bar()
如果我们使用 C1
引用 class C1: P {
func foo() { print("C1.foo") }
func bar() { print("C1.bar") }
}
class C2: C1 {
override func bar() { print("C2.bar") }
}
:
C1
现在在 some P
中,编译器知道它必须使用 let c1: some P = C1()
c1.call_foo() // C1.foo
c1.foo() // C1.foo
c1.call_bar() // C1.bar
c1.bar() // C1.bar
,因此使用 call_bar()
引用 C1.bar()
:
C2
子类 some P
的行为方式仍然与它的超类 let someP: some P = C2()
someP.call_foo() // C1.foo
someP.foo() // C1.foo
someP.call_bar() // C2.bar
someP.bar() // C2.bar
相同,并且它调用了 C2
get 的实现。 (当 sublasses 表现得像它们的父级时,我发现它有点reassuring)。
现在让我们检查原始片段:
C1
它起作用了!