You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift协议与扩展:方法调用时机解析及代码示例求助

嘿,我来帮你理清楚Swift里协议和扩展中方法的调用逻辑,还有你提到的那段代码~

Swift协议与扩展中方法的调用时机

得先明确两种核心场景,这直接决定了代码会调用哪个版本的方法:

1. 协议已声明的方法,扩展提供默认实现

  • 如果某个方法在协议里已经明确声明,哪怕扩展给了它默认实现,当你用协议类型的变量/常量调用这个方法时,会优先执行实现该协议的结构体/类的自定义实现,而不是扩展里的默认版本。
  • 这是因为协议声明的方法会走动态派发,Swift会在运行时判断实际的类型,调用对应的实现。

2. 扩展新增的、协议未声明的方法

  • 如果方法只在扩展里定义,协议本身没有声明它,那么不管实现类有没有重写这个方法,当你用协议类型的变量/常量调用时,都会执行扩展里的默认实现。
  • 这类方法是静态派发的,编译时就确定了调用的版本,不会去匹配实现类的重写逻辑。

解释给定的协议与扩展代码

先把你给出的不完整代码补全成合理的完整版本:

struct Pizza { 
    let ingredients: [String] 
}

protocol Pizzeria {
    func makePizza(ingredients: [String]) -> Pizza
    // 注意:这里注释掉了 makeMargherita 的协议声明
}

extension Pizzeria {
    func makeMargherita() -> Pizza {
        return makePizza(ingredients: ["tomato", "mozzarella"])
    }
}

struct Lombardis: Pizzeria {
    func makePizza(ingredients: [String]) -> Pizza {
        return Pizza(ingredients: ingredients)
    }
    
    // Lombardis 自定义重写了 makeMargherita 方法
    func makeMargherita() -> Pizza {
        return makePizza(ingredients: ["tomato", "mozzarella", "basil"])
    }
}

现在拆解这段代码的逻辑:

1. 核心结构说明

  • Pizza:简单的结构体,用来存储披萨的配料列表。
  • Pizzeria:协议,要求所有遵循它的类型必须实现makePizza(ingredients:)方法,但没有把makeMargherita()纳入协议要求。
  • Pizzeria的扩展:给所有遵循该协议的类型提供了makeMargherita()的默认实现——调用协议要求的makePizza方法,制作经典的玛格丽特披萨(番茄+马苏里拉)。
  • Lombardis:遵循Pizzeria的结构体,不仅实现了协议要求的makePizza方法,还自己重写了makeMargherita,做了一款加罗勒的定制版玛格丽特。

2. 不同调用场景的行为差异

场景一:用具体类型(Lombardis)调用

let myPizzeria = Lombardis()
let pizza = myPizzeria.makeMargherita()
// 这里会调用 Lombardis 自己重写的版本,得到带罗勒的玛格丽特披萨

因为变量是明确的Lombardis类型,Swift直接调用该类型的方法实现。

场景二:用协议类型(Pizzeria)调用

let myPizzeria: Pizzeria = Lombardis()
let pizza = myPizzeria.makeMargherita()
// 这里会调用扩展里的默认版本,得到只有番茄+马苏里拉的披萨

原因是makeMargherita()没有在Pizzeria协议里声明,属于扩展新增的方法,所以当变量是协议类型时,会执行扩展的默认实现,哪怕Lombardis重写了它。

如果把协议里的makeMargherita()注释去掉呢?

如果修改协议,把makeMargherita()纳入协议要求:

protocol Pizzeria {
    func makePizza(ingredients: [String]) -> Pizza
    func makeMargherita() -> Pizza // 取消注释,加入协议声明
}

这时候再用协议类型调用:

let myPizzeria: Pizzeria = Lombardis()
let pizza = myPizzeria.makeMargherita()
// 现在会调用 Lombardis 的重写版本,因为方法在协议里声明了,走动态派发

内容的提问来源于stack exchange,提问作者PruitIgoe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:19:48