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

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实例能被统一存储:

  1. 定义一个不带关联类型的基础协议,提供通用映射方法:
protocol AnyBaseMapper {
    func mapAny(_ payload: Payload) -> Any
}
  1. 让AnyMapper在PayloadType为Payload时遵循该协议并实现方法:
extension AnyMapper where P == Payload {
    func mapAny(_ payload: Payload) -> Any {
        return map(payload)
    }
}
  1. 将数组元素类型改为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:02:57