考虑以下游乐场:
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应该动态调度(如协议中声明的那样)。
a.f()
b.f()
"AAAA"
"CCCC"
func f() -> String
如果我更改class B为以下形式:
class B
class B: A { func f() -> String { return "BBBB" } }
然后所有三个呼叫将按预期.f()返回"CCCC"。
.f()
我觉得这是Swift编译器中的错误,我在Xcode 7.3.1和8.0-beta3中进行了检查,这两种行为都可以重现。
这实际上是预期的行为吗?
您这里涉及到一些规则。
有时使用静态调度(在这种情况下,我们必须查看var / let的类型以找出将要使用的实现)。
其他时间则使用动态分配(这意味着使用变量内部对象的实现)。
让我们考虑一般的例子
let foo: SomeType1 = SomeType2() foo.f()
我将使用以下定义 classic implementation of f() 指示何时在协议扩展之外(因此在struct / class内部)定义了f()。 default implementation of f()指示何时f()在协议扩展内定义。
我将使用以下定义
classic implementation of f() 指示何时在协议扩展之外(因此在struct / class内部)定义了f()。
classic implementation of f()
default implementation of f()指示何时f()在协议扩展内定义。
default implementation of f()
f()
如果SomeType1是struct/class,则使用自己的“经典”实现,f()然后 应用多态 。
SomeType1
struct/class
这意味着如果SomeType2没有经典的实现,f()则SomeType1.f()使用。否则SomeType2.f()获胜。
SomeType2
SomeType1.f()
SomeType2.f()
如果SomeType1没有的经典实现,f()但具有默认实现,则 关闭多态 。
在这种情况下,let/var胜出类型的默认实现。
let/var
让我们来看你的第一个例子
let a: A = C() a.f() // "AAAA"
在此A中没有它自己的经典实现(因为它不是struct / class),但是具有默认实现。因此,多态被关闭并被A.f()使用。
A.f()
第二个示例的规则相同
let b: B = C() b.f() // "AAAA"
B没有f()的经典实现,但是默认实现为f()。因此,关闭了多态并使用了B.f()(从协议扩展名开始)。
B
B.f()
最后,type的对象位于type C的常量内C。
C
var c:C c.f() // "CCCC"
这C是的经典实现f()。在这种情况下,协议实现将被忽略并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常量中,则会出现编译错误
Foo
let foo: Foo = Foo() foo.f() // error: ambiguous use of 'f()' foo.f() ^ Swift 2.playground:2:23: note: found this candidate extension Beta { func f() -> String { return "Beta"} } ^ Swift 2.playground:6:24: note: found this candidate extension Alpha { func f() -> String { return "Alpha"} }