Swift中指定具体类类型时协议方法的调度机制问询
先回顾一下你提到的WWDC场景:当变量类型是协议类型(比如let object: MyProtocol = MyClass())时,调用协议方法会通过Existential Container,借助协议 witness table(PWT)来查找实现——这个是完全正确的。
那回到你的问题:当变量是具体类类型MyClass时,Swift是怎么处理testFuncA调用的?咱们一步步拆解清楚:
首先看你的代码示例:
protocol MyProtocol { func testFuncA() } extension MyProtocol { func testFuncA() { print("MyProtocol's testFuncA") } } class MyClass: MyProtocol {} let object: MyClass = MyClass() object.testFuncA()
核心结论
这个场景下,既不会用Existential Container,也不会把协议默认实现复制到MyClass的v-table里——Swift会直接进行静态调度,编译期就把调用绑定到协议扩展的默认实现上。
具体机制详解
为什么不用Existential Container?
Existential Container是专门为「协议类型变量」设计的——当编译器不知道变量的具体类型(只知道它遵守某个协议)时,才需要用这个容器存储类型信息、PWT等元数据。而这里object的类型是明确的MyClass,编译器完全知道它的具体类型,根本不需要依赖Existential Container来做动态查找。为什么默认实现不会进MyClass的v-table?
协议扩展的默认实现不属于类的继承体系。只有当MyClass显式实现或重写了testFuncA时,这个方法才会被加入到MyClass的v-table中。在你的例子里,MyClass只是遵守了协议但没有自己实现方法,所以它的v-table里根本没有testFuncA的条目。静态调度的具体流程
- 编译阶段,编译器检查
MyClass是否有自己的testFuncA实现——发现没有。 - 接着编译器会查找
MyClass遵守的协议MyProtocol的扩展,找到其中的默认实现。 - 直接把
object.testFuncA()的调用静态绑定到这个扩展方法上,运行时不需要任何动态查找,直接执行扩展里的代码。
补充:如果MyClass显式实现了方法会怎样?
如果MyClass自己写了testFuncA:
class MyClass: MyProtocol { func testFuncA() { print("MyClass's testFuncA") } }
这时testFuncA会被加入到MyClass的v-table中,调用object.testFuncA()会走动态调度——因为类是引用类型,支持多态,编译器会生成v-table查找的代码,运行时根据对象的实际类型找到对应的实现。
内容的提问来源于stack exchange,提问作者Maize

