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

Swift中如何存储泛型闭包以复用MyFeature的转换逻辑

Swift中如何存储泛型闭包以复用MyFeature的转换逻辑

嘿,你遇到的这个问题确实是泛型闭包存储的典型场景,类型擦除确实是正确的解决方向!我来帮你一步步实现:

核心问题在于MyFeature的Transform是带泛型参数RawJsonType的,直接把它转成Transform<Any>会因为类型不匹配报错——毕竟闭包原本只接受特定类型的输入,不是任意的Any。我们需要做的是用类型擦除把不同输入类型的转换闭包包装成统一的可存储类型。

第一步:创建类型擦除的包装器

先定义一个专门的结构体,把泛型闭包的细节隐藏起来,对外提供统一的接口:

struct AnyFeatureTransform<Value> {
    // 内部存储一个接受Any的闭包,隐藏原泛型类型
    private let _apply: (Any) -> Value?
    
    // 初始化方法接受任意RawJsonType的转换闭包
    init<RawJsonType>(_ transform: @escaping (RawJsonType) -> Value?) {
        self._apply = { input in
            // 尝试把输入转换成原闭包需要的RawJsonType,失败则返回nil
            guard let rawJson = input as? RawJsonType else {
                return nil
            }
            return transform(rawJson)
        }
    }
    
    // 提供适配MyFeature所需的泛型Transform类型的方法
    func asTransform<RawJsonType>() -> ((RawJsonType) -> Value?) {
        return { input in
            self._apply(input)
        }
    }
}

第二步:修改MyFeatureMetadata

把原来的Transform<Any>替换成我们的类型擦除包装器,这样就能正常存储闭包了:

struct MyFeatureMetadata<Value> {
    let name: String
    let id: UUID
    let startDate: Date
    let endDate: Date
    let transform: AnyFeatureTransform<Value>

    init<RawJsonType> (
        name: String,
        id: UUID = UUID(),
        startDate: Date = .distantPast,
        endDate: Date = .distantFuture,
        transform: @escaping (RawJsonType) -> Value?
    ) {
        self.name = name
        self.id = id
        self.startDate = startDate
        self.endDate = endDate
        // 把传入的泛型闭包包装成类型擦除后的对象
        self.transform = AnyFeatureTransform(transform)
    }
}

第三步:按你的需求复用转换逻辑

现在你可以像原来设想的那样定义静态元数据,并且在需要实例化MyFeature时,通过asTransform()方法把包装后的闭包转换成MyFeature需要的泛型类型:

enum SomeFeature: String {
    case basic
    case expert
}

extension MyFeatureMetadata<SomeFeature> {
    static var someFeature = Self(name: "some") { (rawJson: String) in
        SomeFeature(rawValue: rawJson) ?? .expert
    }
}

// 实例化MyFeature的代码
let featureMetadata = MyFeatureMetadata<SomeFeature>.someFeature
let myFeature = MyFeature(
    json: ["featureKey": "basic"], // 这里的JSON值类型要和你定义的转换闭包匹配(比如String)
    startDate: featureMetadata.startDate,
    expirationDate: featureMetadata.endDate,
    transform: featureMetadata.transform.asTransform()
)

为什么这样可行?

类型擦除的本质是把泛型类型的差异封装在内部,对外暴露统一的接口。这里的AnyFeatureTransform把原本只接受特定RawJsonType的闭包,转换成了能接受Any的逻辑——在实际调用时再尝试类型转换,完全兼容MyFeature原本的解析逻辑,同时解决了泛型闭包无法直接存储的问题。

备注:内容来源于stack exchange,提问作者Eric

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 08:53:05