我有一个protocol Request
,其关联类型为Response
,还有一个示例方法getToken
,它返回关联类型为Token
或Error
的Publisher。
但是,我得到一个编译错误“示例方法'getToken'的返回类型要求'RequestType.Response'符合any Token
“。
如何修复此错误并确保RequestType.Response
符合any Token
?任何建议或见解将不胜感激。
func getToken<RequestType: Request>(_ request: RequestType) -> some Publisher<any Token, any Error> where RequestType.Response: Token {
tokenClient.send(request)
}
// error:Return type of instance method 'getToken' requires that 'RequestType.Response' conform to 'any Token'
如果我使用some Publisher<TokenWrapper, any Error>
,它工作得很好,因为在我的应用程序中有几种类型的具体令牌。我不想重复.map(TokenWrapper.init)
这一行。
struct TokenWrapper {
let wrappedValue: any Token
}
// send<RequestType: Request>(_ request: RequestType, encoder: JSONEncoder? = nil, decoder: JSONDecoder = .init()) -> AnyPublisher<RequestType.Response, Error>
// current code works fine
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)
}
// what I want the code looks like
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)
}
既然where子句do constraints RequestType.Response
符合Token
,为什么Xcode仍然抱怨错误?
1条答案
按热度按时间ubof19bj1#
您可能会认为
any Token
在这里的意思是“任何符合Token的类型”,但这不是它的意思。它的意思是“一个符合Token的类型的存在 Package 器”。要求发布的类型是字面上的
any Token
(存在性 Package 器)。而不是“某种符合Token的具体类型”。此外,any Token
本身也不符合Token,因为存在式不符合它们的协议。(您可能会遇到any Error
确实符合Error的事实,但这是编译器仅为Error处理的特殊情况异常。它不适用于任何其他协议。)要做到这一点,您需要一个显式的类型擦除器,这正是您用TokenWrapper创建的。通常情况下,这将被命名为AnyToken,它将符合Token,但这仍然是基本的方法。
要与Publisher的工作方式相匹配,您可能需要重命名此
.eraseToAnyToken
:然后你可能有:
但你不能摆脱类型橡皮擦与这种设计。
从这个问题分开,但一些建议:
我强烈建议重新考虑将Token作为协议。真的是这样吗或者Token可以是一个具体的类型,有多种方法来初始化它?这样做可以大大简化这一切。创建太多的互连协议和泛型是一个典型的错误,网络堆栈是一个非常常见的地方,人们通过使系统的错误部分通用来犯这个错误。
我强烈建议使用async/await而不是合并。在使用新系统时,关于合并的许多棘手的事情变得简单得多,苹果已经从Combine大幅后退。