Swift类型擦除问题:无法将AnyMapper<Payload, [Post]>转为AnyMapper<Payload, User>
Swift中无法将不同类型的AnyMapper存入数组的修复方案
报错代码
struct Payload {} struct User {} struct Post {} protocol Mapper { associatedtype PayloadType associatedtype ResultType func map(_ payload: PayloadType) -> ResultType } class AnyMapper<P, R>: Mapper { private var _mapClouser: (P) -> R init<M: Mapper>(_ mapper: M) where M.PayloadType == P, M.ResultType == R { _mapClouser = mapper.map(_:) } func map(_ payload: P) -> R { _mapClouser(payload) } } class UserMapper: Mapper { func map(_ payload: Payload) -> User { return User() } } class PostsMapper: Mapper { func map(_ payload: Payload) -> [Post] { return [Post(), Post(), Post()] } } let userMapper = AnyMapper(UserMapper()) let postsMapper = AnyMapper(PostsMapper()) // 报错:Cannot convert value of type 'AnyMapper<Payload, [Post]>' to expected element type 'AnyMapper<Payload, User>' var array: [AnyMapper] = [userMapper, postsMapper]
错误原因
AnyMapper<P, R>是泛型类,AnyMapper<Payload, User>和AnyMapper<Payload, [Post]>是完全不同的具体类型。Swift要求数组内所有元素的类型必须一致,编译器无法将这两个不同类型的实例统一到同一个数组中,因此抛出类型转换错误。
修复方案
我们可以通过增加一层无关联类型的协议来做类型擦除,让不同的AnyMapper实例能被统一存储:
- 定义一个不带关联类型的基础协议,提供通用映射方法:
protocol AnyBaseMapper { func mapAny(_ payload: Payload) -> Any }
- 让
AnyMapper在PayloadType为Payload时遵循该协议并实现方法:
extension AnyMapper where P == Payload { func mapAny(_ payload: Payload) -> Any { return map(payload) } }
- 将数组元素类型改为
AnyBaseMapper,即可正常存入两个实例:
var array: [AnyBaseMapper] = [userMapper, postsMapper] // 使用时通过类型转换获取具体结果 let payload = Payload() if let user = array[0].mapAny(payload) as? User { // 处理User类型结果 } if let posts = array[1].mapAny(payload) as? [Post] { // 处理[Post]类型结果 }
更灵活的通用类型擦除方案
如果需要支持任意PayloadType,可以重新设计AnyMapper,基于无关联类型协议实现:
protocol AnyMapperProtocol { func map(_ payload: Any) -> Any } class AnyMapper<P, R>: AnyMapperProtocol { private let _map: (P) -> R init<M: Mapper>(_ mapper: M) where M.PayloadType == P, M.ResultType == R { self._map = mapper.map } func map(_ payload: Any) -> Any { guard let typedPayload = payload as? P else { fatalError("Payload type mismatch") } return _map(typedPayload) } // 保留原有的强类型映射方法 func map(_ payload: P) -> R { return _map(payload) } } // 数组定义为[AnyMapperProtocol] var array: [AnyMapperProtocol] = [userMapper, postsMapper]
这种方案适配范围更广,但使用时需注意类型安全,避免类型转换失败。
内容的提问来源于stack exchange,提问作者GeX
相关产品推荐
相关产品推荐

