子子类中协议默认实现的覆盖不参与动态调度

【字号: 日期:2024-04-13浏览:38作者:雯心
(adsbygoogle = window.adsbygoogle || []).push({}); 如何解决子子类中协议默认实现的覆盖不参与动态调度?

您这里涉及到一些规则。

有时使用静态调度(在这种情况下,我们必须查看var / let的类型以找出将要使用的实现)。

其他时间则使用动态分配(这意味着使用变量内部对象的实现)。

让我们考虑一般的例子

let foo: SomeType1 = SomeType2()foo.f()

我将使用以下定义

classic implementation of f() 指示何时在协议扩展之外(因此在struct / class内部)定义了f()。

default implementation of f()指示何时f()在协议扩展内定义。

动态调度

如果SomeType1是struct/class,则使用自己的“经典”实现,f()然后 。

这意味着如果SomeType2没有经典的实现,f()则SomeType1.f()使用。否则SomeType2.f()获胜。

静态调度

如果SomeType1没有的经典实现,f()但具有默认实现,则 。

在这种情况下,let/var胜出类型的默认实现。

一个。

让我们来看你的第一个例子

let a: A = C()a.f() // 'AAAA'

在此A中没有它自己的经典实现(因为它不是struct / class),但是具有默认实现。因此,多态被关闭并被A.f()使用。

b。

第二个示例的规则相同

let b: B = C()b.f() // 'AAAA'

B没有f()的经典实现,但是默认实现为f()。因此,关闭了多态并使用了B.f()(从协议扩展名开始)。

C。

最后,type的对象位于type C的常量内C。

var c:Cc.f() // 'CCCC'

这C是的经典实现f()。在这种情况下,协议实现将被忽略并C.f()使用。

更多

我们来看另一个例子

protocol Alpha { }extension Alpha { func f() -> String { return 'Alpha'} }protocol Beta { }extension Beta { func f() -> String { return 'Beta'} }class Foo: Alpha, Beta { }let alpha: Alpha = Foo()alpha.f() // 'Alpha'let beta: Beta = Foo()beta.f() // 'Beta'

如您所见,包含值的常量类型将获胜。如果将Foo对象放入Foo常量中,则会出现编译错误

let foo: Foo = Foo()foo.f() //error: ambiguous use of ’f()’foo.f()^Swift 2.playground:2:23: note: found this candidateextension Beta { func f() -> String { return 'Beta'} } ^Swift 2.playground:6:24: note: found this candidateextension Alpha { func f() -> String { return 'Alpha'} }解决方法

考虑以下游乐场:

protocol A { func f() -> String}extension A { func f() -> String { return 'AAAA' }}class B: A {}class C: B { func f() -> String { return 'CCCC' }}let a: A = C()let b: B = C()let c: C = C()a.f() // 'AAAA' - why?b.f() // 'AAAA' - why?c.f() // 'CCCC'

我不知道为什么a.f()然后b.f()返回'AAAA'-它们应该返回,'CCCC'因为func f() ->String应该动态调度(如协议中声明的那样)。

如果我更改class B为以下形式:

class B: A { func f() -> String { return 'BBBB' }}

然后所有三个呼叫将按预期.f()返回'CCCC'。

我觉得这是Swift编译器中的错误,我在Xcode 7.3.1和8.0-beta3中进行了检查,这两种行为都可以重现。

这实际上是预期的行为吗?

相关文章: