4-9.【协议导向编程】举例说明 func foo() 在 protocol extension 中和 class 实现中如何产生不同结果。

3 阅读2分钟

一、场景一:foo()protocol extension

1️⃣ 定义协议 + extension

protocol Fooable {}

extension Fooable {
    func foo() {
        print("foo from protocol extension")
    }
}

2️⃣ 具体类型“实现”同名方法

struct A: Fooable {
    func foo() {
        print("foo from A")
    }
}

⚠️ 注意:
这里并不是 override
只是“恰好同名的普通方法”


3️⃣ 不同调用方式 → 不同结果

✅ 通过具体类型调用

let a = A()
a.foo()

输出:

foo from A

原因:
👉 编译器知道 a 是 A
👉 直接静态绑定 A.foo()


❌ 通过协议类型调用(关键)

let p: Fooable = A()
p.foo()

输出:

foo from protocol extension

🔥 同一个对象,结果变了


4️⃣ 为什么?

因为:

  • foo() 没有写在 protocol 里
  • protocol 并不知道有 foo()
  • extension 里的 foo()静态派发
  • 不走 witness table
  • 编译期直接绑定 extension 实现

📌 struct A 的 foo() 根本不参与多态


二、场景二:foo()class 继承体系中

现在我们用 class,做完全一样的事情。


1️⃣ 基类定义 foo()

class Base {
    func foo() {
        print("foo from Base")
    }
}

2️⃣ 子类 override

class B: Base {
    override func foo() {
        print("foo from B")
    }
}

3️⃣ 通过父类类型调用

let b: Base = B()
b.foo()

输出:

foo from B

4️⃣ 为什么这里“没问题”?

因为:

  • class 方法默认走 vtable
  • override 是语言级语义
  • 调用是 动态派发
  • 运行时根据真实类型决定

👉 这才是传统 OOP 的多态


三、把两种情况放在一起对比(核心)

场景变量静态类型调用机制输出
protocol extensionFooable静态派发extension 实现
protocol extensionA静态派发A.foo()
class overrideBase动态派发B.foo()

四、如果你“想让协议也像 class 一样”怎么办?

✅ 正确写法:foo() 写进 protocol

protocol Fooable {
    func foo()
}

extension Fooable {
    func foo() {
        print("foo from default implementation")
    }
}

struct A: Fooable {
    func foo() {
        print("foo from A")
    }
}

现在:

let p: Fooable = A()
p.foo()

输出:

foo from A

🎯 因为:

  • foo() 是协议要求
  • 进入 witness table
  • 动态派发生效

五、一句话点破本质(非常重要)

protocol extension 里的方法不是“可 override 的接口”,
它只是“在协议命名空间下的静态函数”。

而:

class 的方法才是天生为 override 和多态设计的。


六、记住这个判断公式(以后秒懂)

看到一个 foo(),你只问两件事:

  1. 它写在 protocol 本体里了吗?
  2. 我是通过 protocol 类型调用的吗?
  • ① NO + ② YES → ❌ extension 实现
  • ① YES → ✅ 多态
  • class + override → ✅ 多态

七、终极总结(可以当面试答案)

func foo()
在 protocol extension 中是 静态派发的默认实现
在 class 中是 通过 vtable 动态派发的 override 点
所以即使名字一样,语义完全不同。