一、一句话结论(先背下来)
只有当方法“写在 protocol 本体中”时,
conforming type 的实现才会覆盖(override)protocol extension 的默认实现。
否则,永远不会被覆盖。
二、唯一会被覆盖的情况(正确示例)
✅ 情况:方法在 protocol 中声明
protocol Greeter {
func greet()
}
默认实现(extension)
extension Greeter {
func greet() {
print("default greet")
}
}
类型提供自己的实现
struct Person: Greeter {
func greet() {
print("person greet")
}
}
调用结果(关键)
let g: Greeter = Person()
g.greet()
输出:
person greet
🎯 原因:
greet()是协议要求- extension 提供的是默认实现
Person.greet()被放入 witness table- 运行时动态派发
👉 这是“被覆盖”的唯一合法方式
三、所有“不会被覆盖”的情况(常见误区)
❌ 情况 1:方法只在 extension 中
protocol Greeter {}
extension Greeter {
func greet() {
print("default greet")
}
}
struct Person: Greeter {
func greet() {
print("person greet")
}
}
let g: Greeter = Person()
g.greet()
输出:
default greet
🔥 Person 的实现完全没被用到
❌ 情况 2:子协议 extension 试图“覆盖”父协议
protocol A {}
extension A {
func foo() { print("A") }
}
protocol B: A {}
extension B {
func foo() { print("B") }
}
let x: A = S()
x.foo() // A
❌ 子协议 extension 不能 override 父协议 extension
❌ 情况 3:多个协议 extension 同名方法
protocol A {}
protocol B {}
extension A {
func foo() { print("A") }
}
extension B {
func foo() { print("B") }
}
👉 没有“覆盖关系”,只有静态视角切换
四、一个完整判断表(收藏级)
| 条件 | 会覆盖吗? |
|---|---|
| 方法在 protocol 中声明 | ✅ |
| 默认实现在 extension 中 | ✅ |
| conforming type 实现该方法 | ✅ |
| 方法只在 extension 中 | ❌ |
| extension 想 override extension | ❌ |
| 子协议 extension 覆盖父协议 | ❌ |
| 多协议 extension 同名 | ❌ |
五、Swift 编译器视角(为什么只能这样)
Swift 的设计是:
- protocol 声明 = 行为契约
- witness table 只记录契约
- extension 新增方法 ≈ 静态函数
- 不进 witness table
- 无法动态派发
👉 所以:
编译器根本不知道 extension 方法“可以被覆盖”
六、工程级设计建议(非常重要)
🟢 你应该这样设计协议
protocol Renderer {
func render() // 多态点
}
extension Renderer {
func render() {
setup()
draw()
}
func setup() { ... } // 工具方法
}
struct MetalRenderer: Renderer {
func draw() { ... } // 差异点
}
🔴 永远不要指望这种写法“被覆盖”
extension Renderer {
func draw() { ... }
}
七、一句话终极总结(面试级)
protocol extension 的默认实现,
只有在“补充协议要求”时才会被覆盖,
任何 extension 新增的方法都不会参与多态。