在子子类中覆盖协议默认实现不参与动态分派

时间:2016-08-17 23:53:20

标签: swift protocols

考虑以下操场:

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中检查过,这种行为在两者中都是可重现的。

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

1 个答案:

答案 0 :(得分:4)

这里有几个规则。

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

其他时候使用Dynamic Dispatch(这意味着使用变量内部对象的实现)。

让我们考虑一般的例子

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

我将使用以下定义

     
      
  • classic implementation of f()表示何时在协议扩展之外定义f()(所以在struct / class中)。

  •   
  • default implementation of f()表示在协议扩展名中定义f()的时间。

  •   

动态调度

如果SomeType1struct/class,那么f()拥有"经典"实施SomeType2然后多态性应用

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

静态调度

如果f()没有let/var的经典实现但具有默认实现,则多态已关闭

在这种情况下,let a: A = C() a.f() // "AAAA" 类型的默认实现获胜。

一个。

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

A.f()

在这个A中没有它自己的经典实现(因为它不是结构/类)但是有一个默认实现。所以关闭多态性并使用let b: B = C() b.f() // "AAAA"

第二个例子的相同规则

B

f()没有f()的经典实现,但默认实现为B.f()。因此,关闭多态性并使用C(来自协议扩展)。

最后,C类型的对象位于var c:C c.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 candidate extension Beta { func f() -> String { return "Beta"} } ^ Swift 2.playground:6:24: note: found this candidate extension Alpha { func f() -> String { return "Alpha"} } 常量内,则会出现编译错误

class Example {
  public static void main(String args[]) {
         BlockingQueue<String> queue = new ArrayBlockingQueue<>(1000);
    Producer producer = new Producer(queue);
    Consumer consumer = new Consumer(queue);
    ExecutorService executor = Executors.newCachedThreadPool();
//    executor.execute(consumer);
    Future producerFuture = executor.submit(producer);
    Future consumerFuture = executor.submit(consumer);
    try {
      producerFuture.get();
      consumerFuture.get();
    } catch (InterruptedException e) {
      LOG.error("Failed");
    }
    executor.shutdown();
    executor.awaitTermination(10, TimeUnit.MILLISECONDS);
  }
}