Swift协变类型与泛型转换问题求助:UseCase类类型转换失败
解决Swift泛型UseCase协变转换问题
错误原因
Swift的泛型类默认是**不变(invariant)**的,也就是说UseCase<P, R>和UseCase<Any, Any>属于完全独立的类型,哪怕P和R是Any的子类型,也无法直接将UseCase<P, R>实例转换为UseCase<Any, Any>返回——这就是你看到报错的核心原因。
解决方案
要实现类似的类型擦除效果,你需要通过泛型协议协变+类型擦除类来完成,或者直接将原逻辑包装到新的UseCase<Any, Any>实例中,以下是两种可行方案:
方案1:利用协变协议+类型擦除(推荐)
首先重构你的协议,使用Swift 5.7+支持的out关键字标记协变类型参数,让协议支持协变转换:
// 定义支持协变的协议,Input用in(逆变),Output用out(协变) protocol ProtocolUseCase<Input, Output> { associatedtype Input associatedtype Output // 假设协议包含核心执行方法,可根据实际业务调整 func execute(with input: Input) async throws -> Output }
然后修改UseCase类,并实现toAny()方法返回类型擦除后的协议实例:
class UseCase<P, R>: ProtocolUseCase { // 示例核心方法,替换为你的实际业务逻辑 func execute(with input: P) async throws -> R { // 业务逻辑实现 ... } func toAny() -> any ProtocolUseCase<Any, Any> { // 用类型擦除类包装当前实例的逻辑 AnyUseCase<Any, Any> { [weak self] input in guard let self = self else { throw NSError(domain: "UseCase", code: -1, userInfo: [NSLocalizedDescriptionKey: "实例已释放"]) } // 将Any类型的输入转换为当前UseCase需要的P类型 guard let typedInput = input as? P else { throw NSError(domain: "UseCase", code: -2, userInfo: [NSLocalizedDescriptionKey: "输入类型不匹配"]) } // 执行原逻辑并将结果转为Any let result = try await self.execute(with: typedInput) return result as Any } } } // 类型擦除类,用于包装任意ProtocolUseCase实例 class AnyUseCase<Input, Output>: ProtocolUseCase { private let executeClosure: (Input) async throws -> Output init(execute: @escaping (Input) async throws -> Output) { self.executeClosure = execute } func execute(with input: Input) async throws -> Output { try await executeClosure(input) } }
方案2:直接包装为UseCase<Any, Any>实例
如果你一定要返回UseCase<Any, Any>类型,可以创建一个新实例,将当前UseCase的逻辑包装进去:
class UseCase<P, R>: ProtocolUseCase { func execute(with input: P) async throws -> R { // 你的业务逻辑 ... } func toAny() -> UseCase<Any, Any> { UseCase<Any, Any> { input in guard let typedInput = input as? P else { throw NSError(domain: "UseCaseError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效的输入类型"]) } let result = try await self.execute(with: typedInput) return result as Any } } }
关键说明
Swift中只有泛型协议可以通过in(逆变)和out(协变)关键字声明类型参数的变化性,泛型类本身不支持协变/逆变,所以直接转换类型是行不通的,必须通过包装或类型擦除的方式间接实现需求。
内容的提问来源于stack exchange,提问作者Caio Sanchez Christino
相关产品推荐
相关产品推荐

