Swift带关联类型的协议方法返回类型错误的解决办法
问题
定义了带有关联类型Response的Request协议,以及返回关联类型Token或Error的Publisher实例方法getToken,但编译报错:
Return type of instance method 'getToken' requires that 'RequestType.Response' conform to any Token
应用存在多种具体Token类型,当前用TokenWrapper配合.map(TokenWrapper.init)可正常运行,但不想重复该代码,期望直接返回some Publisher<any Token, any Error>。即使添加了where子句约束RequestType.Response遵循Token,Xcode仍报错,如何修复?
报错代码
func getToken<RequestType: Request>(_ request: RequestType) -> some Publisher<any Token, any Error> where RequestType.Response: Token { tokenClient.send(request) }
错误提示:
Return type of instance method 'getToken' requires that 'RequestType.Response' conform to 'any Token'
当前可用代码(使用包装器)
struct TokenWrapper { let wrappedValue: any Token } // send方法定义 // send<RequestType: Request>(_ request: RequestType, encoder: JSONEncoder? = nil, decoder: JSONDecoder = .init()) -> AnyPublisher<RequestType.Response, Error> func getToken<RequestType: Request>(_ request: RequestType) -> some Publisher<TokenWrapper, any Error> { tokenClient.send(request) .map(TokenWrapper.init) } func handle(_ pubilsher: some Publisher<TokenWrapper, any Error>) { publihsher ... ... .store(in: subscriptions) }
期望实现的代码
func getToken<RequestType: Request>(_ request: RequestType) -> some Publisher<any Token, any Error> where RequestType.Response: Token { tokenClient.send(request) } func handle(_ pubilsher: some Publisher<any Token, any Error>) { publihsher .map(TokenWrapper.init) ... ... .store(in: subscriptions) }
解决方案
问题源于Swift类型系统对存在类型(any Token)的处理规则:tokenClient.send(request)返回的是AnyPublisher<RequestType.Response, Error>,尽管RequestType.Response遵循Token协议,但Swift不会自动将具体类型隐式转为存在类型any Token,必须显式转换。
修改getToken方法,通过.map将具体的RequestType.Response实例转为any Token即可:
func getToken<RequestType: Request>(_ request: RequestType) -> some Publisher<any Token, any Error> where RequestType.Response: Token { tokenClient.send(request) .map { $0 as any Token } // 显式转换为存在类型 }
原理说明
RequestType.Response是遵循Token的具体类型,而返回值要求的是存在类型any Token,显式转换能让Swift确认类型兼容性。- 该转换是安全的,因为
where子句已约束RequestType.Response必须遵循Token协议。 - 修改后无需再用
TokenWrapper做中间包装,直接返回符合期望的Publisher<any Token, any Error>。
内容的提问来源于stack exchange,提问作者shinolr

