能否为带关联值的枚举创建泛型扩展以简化取值?
为带关联值的Swift枚举实现简洁的关联值提取
我们定义了如下枚举:
enum Line { case horizontal(CGFloat) case vertical(CGFloat) case diagonal(CGFloat, CGFloat) }
常规的关联值提取方法都不够简洁,现在想通过泛型扩展实现示例中的简洁语法:
示例1:提取单关联值
let lineH = Line.horizontal(10) if let val = lineH.is(Line.horizontal) { print("lineHorizontalValue: \(val)") // 输出:lineHorizontalValue: 10 }
示例2:提取多关联值
let lineD = Line.diagonal(10, 20) if let (point1, point2) = lineD.is(Line.diagonal) { print("lineDiagonalValue: \(point1), \(point2)") // 输出:lineDiagonalValue: 10, 20 }
通用泛型实现方案
可以通过为所有枚举添加泛型扩展,结合模式匹配来实现这个需求,既保证类型安全,又能复用逻辑:
import CoreGraphics enum Line { case horizontal(CGFloat) case vertical(CGFloat) case diagonal(CGFloat, CGFloat) } extension Equatable { func `is`<Value>(_ case: (Value) -> Self) -> Value? { guard let mirror = Mirror(reflecting: self).children.first else { return nil } let value = mirror.value if let typedValue = value as? Value, `case`(typedValue) == self { return typedValue } return nil } func `is`<V1, V2>(_ case: (V1, V2) -> Self) -> (V1, V2)? { guard let mirror = Mirror(reflecting: self).children.first else { return nil } let value = mirror.value if let typedValue = value as? (V1, V2), `case`(typedValue.0, typedValue.1) == self { return typedValue } return nil } }
代码说明
- 为所有
Equatable类型(带关联值的枚举若关联值都遵循Equatable,Swift 5.1+会自动合成该协议实现)添加扩展,让所有枚举都能复用这套逻辑。 - 利用
Mirror反射获取枚举的关联值,再通过传入的case构造函数反向验证是否匹配当前实例。 - 重载了两个
is方法,分别处理单关联值和双关联值场景,如需支持更多关联值,可继续添加对应参数个数的重载方法。
注意事项
- 若追求极致性能,可针对特定枚举写专属扩展(直接用模式匹配替代反射),反射的性能损耗在大多数业务场景下可忽略。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

