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

Swift结构体Runtime Polymorphism实现的协议适配问题

报错根因

Swift 对协议合规的校验是严格的签名匹配:类型要实现某协议,其属性、方法的参数/返回值类型必须和协议声明完全一致。
你定义的upperCase_Conformance协议要求:

  • 可读写属性myVal的类型为lowerCase_Conformance(任意实现了小写协议的存在类型)
  • 构造方法init(val:)的入参类型为lowerCase_Conformance
    但你在A、B的实现中,分别将myVal写死为具体类型a、b,构造方法也仅接受对应具体类型,和协议要求的签名不匹配,因此编译器判定两个类型不符合协议约束。
实现方案

你的核心诉求不需要复杂的泛型或类型判断,根据使用场景优先选第一种方案即可,完全满足「同数组存储、遍历直接调用printMe()无类型判断」的要求。

方案1:精简协议定义(推荐,类型安全无额外开销)

你把实例存入数组后,只会对外调用printMe()方法,完全不需要在协议层面约束内部存储属性和构造方法——这两部分属于类型的内部实现细节,不需要暴露给协议使用者。
直接把upperCase_Conformance中多余的属性、构造方法要求删掉即可,A、B的原有实现完全不需要改动:

/// lowerCase objects must have a value and an action to perform using that value
protocol lowerCase_Conformance {
    var value: Double { get set }
    init(val: Double)
    func compute() -> Double
}

/// 仅对外暴露需要调用的方法,内部实现由各类型自行管理
protocol upperCase_Conformance {
    func printMe()
}

/// Squared operator
struct a: lowerCase_Conformance {
    public var value: Double
    public init (val: Double) {
        self.value = val
    }
    public func compute() -> Double {
        return self.value * self.value
    }
}

/// Housing for the Squared operator
struct A: upperCase_Conformance {
    public var myVal: a
    public init (val: a) {
        self.myVal = val
    }
    public func printMe() {
        print("\(self.myVal.value) Squared is \(self.myVal.compute())")
    }
}

/// Increment operator
struct b: lowerCase_Conformance {
    public var value: Double
    public init (val: Double) {
        self.value = val
    }
    public func compute() -> Double {
        return self.value + 1
    }
}

/// Housing for the Increment operator
struct B: upperCase_Conformance {
    public var myVal: b
    public init (val: b) {
        self.myVal = val
    }
    public func printMe() {
        print("\(self.myVal.value) Incremented is \(self.myVal.compute())")
    }
}

// 数组存储和遍历逻辑完全正常,不需要任何类型判断
var workToDo: [upperCase_Conformance] = [
    A(val: a(val: 2)),
    A(val: a(val: 4)),
    B(val: b(val: 2)),
    B(val: b(val: 4))
]

for item in workToDo {
    item.printMe()
}

运行后输出符合预期:

2.0 Squared is 4.0
4.0 Squared is 16.0
2.0 Incremented is 3.0
4.0 Incremented is 5.0

这个方案完全保留类型安全:A只能持有a类型的实例,B只能持有b类型的实例,不会出现逻辑和文案不匹配的问题,同时动态派发的开销极低。

方案2:保留协议对内部存储的约束

如果你确实需要在协议层面强制所有遵循upperCase_Conformance的类型都必须持有lowerCase_Conformance实例、实现对应构造方法,只需要把A、B中的myVal属性和构造方法入参的类型改成协议要求的lowerCase_Conformance即可:

/// upperCase objects must store a lowerCase object and a way to display the computations being done by the lowerCase object.
protocol upperCase_Conformance {
    var myVal: lowerCase_Conformance { get set }
    init(val: lowerCase_Conformance)
    func printMe()
}

struct A: upperCase_Conformance {
    public var myVal: lowerCase_Conformance
    public init (val: lowerCase_Conformance) {
        self.myVal = val
    }
    public func printMe() {
        // 需要做类型校验,避免传入非a类型的实例导致文案错误
        guard let val = myVal as? a else { return }
        print("\(val.value) Squared is \(val.compute())")
    }
}

struct B: upperCase_Conformance {
    public var myVal: lowerCase_Conformance
    public init (val: lowerCase_Conformance) {
        self.myVal = val
    }
    public func printMe() {
        guard let val = myVal as? b else { return }
        print("\(val.value) Incremented is \(val.compute())")
    }
}

这个方案可以正常编译运行,但缺点是丢失了编译期类型安全,需要在printMe中做运行时类型判断,不推荐优先使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 01:39:19