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

Swift中如何向数组添加泛型项?解决类型不匹配报错

解决Swift中泛型闭包存入数组的类型不匹配问题

问题分析

你遇到的核心问题是:泛型函数get中的completion是针对具体T: Decodable类型的闭包(Result<T, ApiError>),但数组messages定义的completion类型是Result<any Decodable, ApiError>,两者无法直接转换——因为Result<T, ...>和Result<any Decodable, ...>属于不同的类型,Swift不允许直接隐式转换。

解决方案:用类型擦除包装类统一类型

要存储不同泛型类型的闭包,我们需要用类型擦除的方式,把泛型闭包封装成非泛型的可存储类型:

步骤1:定义类型擦除包装类

这个类会把具体泛型类型的闭包转换成统一的非泛型接口:

// 先确保你的ApiError包含类型不匹配的错误 case(如果没有可以添加)
enum ApiError: Error {
    case typeMismatch
    // 其他已有的错误 case...
}

class AnyCompletionWrapper {
    private let handleClosure: (Result<any Decodable, ApiError>) -> Void
    
    // 初始化时接收具体泛型类型的completion
    init<T: Decodable>(_ completion: @escaping (Result<T, ApiError>) -> Void) {
        self.handleClosure = { result in
            switch result {
            case .success(let decodedValue as T):
                // 类型匹配,调用原completion返回正确类型
                completion(.success(decodedValue))
            case .failure(let error):
                // 直接传递错误
                completion(.failure(error))
            case .success:
                // 类型不匹配时返回对应的错误
                completion(.failure(.typeMismatch))
            }
        }
    }
    
    // 对外暴露调用闭包的方法
    func handle(_ result: Result<any Decodable, ApiError>) {
        handleClosure(result)
    }
}

步骤2:修改数组类型

把原来的数组改成存储AnyCompletionWrapper类型的completion:

var messages: [(url: URL, completion: AnyCompletionWrapper)] = []

步骤3:在get函数中存入数组

现在可以正常append泛型闭包了,因为我们把它包装成了AnyCompletionWrapper:

func get<T: Decodable>(from url: URL, type: T.Type, completion: @escaping (Result<T, ApiError>) -> ()) {
    messages.append((url, AnyCompletionWrapper(completion)))
}

步骤4:测试时调用闭包

当你需要模拟API返回、触发completion时,只需取出数组中的AnyCompletionWrapper,调用handle方法即可:

// 示例:模拟返回TimetableModel
let mockTimetable = TimetableModel(/* 初始化模拟数据 */)
if let message = messages.first(where: { $0.url == targetUrl }) {
    message.completion.handle(.success(mockTimetable))
}

补充说明

这种方式既保留了泛型闭包的类型安全性,又能统一存储不同泛型类型的闭包,完全适配你的测试场景——比如原函数getTimeTable调用httpClient.get时,传入的TimetableModel类型的completion会被正确包装存入数组,后续模拟返回时能准确触发对应的回调。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 05:22:17