考虑以下游乐场:
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"
Run Code Online (Sandbox Code Playgroud)
我不明白为什么a.f()并b.f()返回"AAAA"- 它们应该返回,"CCCC"因为func f() -> String应该动态调度(因为它在协议中声明).
如果我改成class B这样:
class B: A {
func f() -> String { return "BBBB" }
}
Run Code Online (Sandbox Code Playgroud)
然后所有三个调用按预期.f()返回"CCCC".
我觉得这是Swift编译器中的一个错误,我在Xcode 7.3.1和8.0-beta3中检查过,这种行为在两者中都是可重现的.
这实际上是预期的行为吗?
这里涉及到几条规则。
有时使用静态调度(在这种情况下,我们必须查看 var/let 的类型以找出将使用的实现)。
其他时候则使用动态调度(这意味着使用变量内部对象的实现)。
让我们考虑一下一般的例子
let foo: SomeType1 = SomeType2()
foo.f()
Run Code Online (Sandbox Code Playgroud)
我将使用以下定义
classic implementation of f()指示 f() 何时在协议扩展之外定义(因此在结构/类内部)。
default implementation of f()指示何时f()在协议扩展内定义。
如果SomeType1是一个struct/class有它自己的“经典”实现,f()那么应用多态性。
这意味着 ifSomeType2没有f()then的经典实现SomeType1.f()。否则SomeType2.f()获胜。
如果SomeType1没有 的经典实现,f()但有默认实现,则多态性被关闭。
在这种情况下,默认实现获胜类型let/var。
让我们看看你的第一个例子
let a: A = C()
a.f() // "AAAA"
Run Code Online (Sandbox Code Playgroud)
在此 A 没有自己的经典实现(因为它不是结构/类),但有一个默认实现。所以多态性被关闭并被A.f()使用。
第二个例子的规则相同
let b: B = C()
b.f() // "AAAA"
Run Code Online (Sandbox Code Playgroud)
B没有 f() 的经典实现,但有f(). 因此,多态性被关闭并B.f()使用(来自协议扩展)。
最后, type 的对象C位于 type 的常量内C。
var c:C
c.f() // "CCCC"
Run Code Online (Sandbox Code Playgroud)
这里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"
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,包含该值的常量类型再次获胜。如果将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"} }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1798 次 |
| 最近记录: |