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
相关产品推荐
相关产品推荐

