Swift中注入存储带关联类型的MapperProtocol遇错误如何解决?
解决Swift中带关联类型协议的注入问题
你的代码出现错误的核心原因是:带有关联类型(associatedtype)的协议不能直接作为变量类型或参数类型使用。Swift编译器需要明确知道协议关联类型的具体类型,直接声明private let mapper: MapperProtocol时,编译器无法推断T和U的具体类型,同时parse方法中传入Data类型的data给mapper.map(item:)也存在类型不匹配的隐患。
下面提供两种可行的解决方案:
方案一:给TrackParser添加泛型约束
通过泛型参数约束TrackParser依赖的Mapper必须符合MapperProtocol,同时明确指定关联类型的具体类型(T=Data,U=Track),保证类型安全:
protocol MapperProtocol { associatedtype T associatedtype U func map(item: T) -> U? } protocol ParserProtocol { associatedtype T associatedtype U func parse(from: T) -> U? } class TrackParser<Mapper: MapperProtocol>: ParserProtocol where Mapper.T == Data, Mapper.U == Track { typealias T = String typealias U = Track private let mapper: Mapper init(mapper: Mapper) { self.mapper = mapper } func parse(from path: String) -> Track? { guard let data = try? Data(contentsOf: URL(filePath: path)) else { return nil } return mapper.map(item: data) } }
这种方式完全保留类型安全,TrackParser初始化时只需传入符合约束的任意MapperProtocol实现类,无需知道具体类型。
方案二:使用类型擦除包装MapperProtocol
如果不想让TrackParser变成泛型类,可以通过类型擦除创建一个AnyMapper类,隐藏MapperProtocol的具体实现类型:
第一步:实现类型擦除的AnyMapper
class AnyMapper<Input, Output>: MapperProtocol { private let mapClosure: (Input) -> Output? init<ConcreteMapper: MapperProtocol>(_ mapper: ConcreteMapper) where ConcreteMapper.T == Input, ConcreteMapper.U == Output { mapClosure = mapper.map } func map(item: Input) -> Output? { return mapClosure(item) } }
第二步:修改TrackParser使用AnyMapper
class TrackParser: ParserProtocol { typealias T = String typealias U = Track private let mapper: AnyMapper<Data, Track> // 直接接受AnyMapper的初始化方法 init(mapper: AnyMapper<Data, Track>) { self.mapper = mapper } // 可选:提供更友好的初始化方法,直接接受符合条件的MapperProtocol实例 convenience init<ConcreteMapper: MapperProtocol>(mapper: ConcreteMapper) where ConcreteMapper.T == Data, ConcreteMapper.U == Track { self.init(mapper: AnyMapper(mapper)) } func parse(from path: String) -> Track? { guard let data = try? Data(contentsOf: URL(filePath: path)) else { return nil } return mapper.map(item: data) } }
这种方式下TrackParser是非泛型类,适合需要统一类型管理的场景(比如将多个TrackParser实例存入数组),同时依然可以注入任意符合要求的MapperProtocol实现。
内容的提问来源于stack exchange,提问作者Burak Akyalçın
相关产品推荐
相关产品推荐

