考虑以下操场:
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中检查过,这种行为在两者中都是可重现的。
这实际上是预期的行为吗?
答案 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()
的时间。
如果SomeType1
是struct/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);
}
}