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

能否为带关联值的枚举创建泛型扩展以简化取值?

为带关联值的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
    }
}

代码说明

  1. 为所有Equatable类型(带关联值的枚举若关联值都遵循Equatable,Swift 5.1+会自动合成该协议实现)添加扩展,让所有枚举都能复用这套逻辑。
  2. 利用Mirror反射获取枚举的关联值,再通过传入的case构造函数反向验证是否匹配当前实例。
  3. 重载了两个is方法,分别处理单关联值和双关联值场景,如需支持更多关联值,可继续添加对应参数个数的重载方法。

注意事项

  • 若追求极致性能,可针对特定枚举写专属扩展(直接用模式匹配替代反射),反射的性能损耗在大多数业务场景下可忽略。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 14:52:06