如何将Measurement<Unit>向下转换为其子类 解决Swift类型转换报错
Measurement 向下转换为具体类型的最优实现方案
强转失败原因
Swift 中的泛型类型默认是不变的,即便 UnitLength 是 Dimension 的子类,Measurement<Dimension> 和 Measurement<UnitLength> 也属于完全无关的类型,因此直接执行强转操作会触发运行时崩溃,Xcode 也会提前抛出如下警告:
Cast from
Measurement<Dimension>to unrelated typeMeasurement<UnitLength>always fails
优雅的泛型转换方案
我们可以给 Measurement 扩展一个泛型转换方法,无需每次手动构建新对象,自动兼容所有 Dimension 子类的转换需求,同时返回可选值保证类型安全:
extension Measurement where UnitType == Dimension { /// 安全转换为指定单位类型的 Measurement func `as`<T: Dimension>(_ unitType: T.Type) -> Measurement<T>? { guard let targetUnit = unit as? T else { return nil } return .init(value: value, unit: targetUnit) } }
使用示例
// 原始的 Dimension 类型 Measurement var thing = Measurement(value: 24, unit: UnitLength.meters) as Measurement<Dimension> // 转换为 UnitLength 类型 if let lengthMeasurement = thing.as(UnitLength.self) { print(lengthMeasurement) // 输出:24.0 m } // 转换为错误类型会返回 nil,不会崩溃 let wrongConversion = thing.as(UnitMass.self) // nil
多类型分发场景优化
如果需要处理多种单位类型的逻辑分支,可以搭配类型匹配使用,无需重复手写对象创建代码:
switch thing.unit { case is UnitLength: guard let length = thing.as(UnitLength.self) else { break } // 处理长度相关逻辑 case is UnitMass: guard let mass = thing.as(UnitMass.self) else { break } // 处理质量相关逻辑 case is UnitTemperature: guard let temperature = thing.as(UnitTemperature.self) else { break } // 处理温度相关逻辑 default: break }
内容的提问来源于stack exchange,提问作者Vincent Romani
相关产品推荐
相关产品推荐

