4-11.【协议导向编程】什么情况下 protocol extension 的默认实现会被覆盖?

2 阅读2分钟

一、一句话结论(先背下来)

只有当方法“写在 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 新增的方法都不会参与多态。