我们需要一些建议。我正在尝试做这样的抽象,所以我有很多不同的响应。在项目的某个时候,我们意识到我们的一些响应具有 id 属性,我们想为这些响应制定一些通用逻辑,而不用关心这个响应是什么。唯一重要的是那些 Responses 包含
id
字段。我们引入了WithIdResponse
,并为包含id
的响应创建了扩展,并且在已实现架构的上下文中很有用。
接下来我们为
Single
创建了 Reactive 虚拟扩展,它做简单的映射 WithIdResponse?
->
String?
我们称这个运算符为 id
.
现在 Swift 的问题是,当我们使用这个
id
运算符时,编译器会出现这样的错误:Referencing instance method 'id()' on 'PrimitiveSequence' requires the types 'ItemAResponse' and 'any WithIdResponse' be equivalent
我们试图理解这条消息,但我们失败了。我们的假设在这里做错了什么吗?
import Foundation
import RxSwift
protocol WithIdResponse {
var id: String { get }
}
extension PrimitiveSequence where Element == WithIdResponse?, Trait == SingleTrait {
func id() -> Single<String?> {
self.map { $0?.id }
}
}
struct ItemAResponse {
let id: String
}
extension ItemAResponse: WithIdResponse {}
struct ItemBResponse {
let id: String
}
extension ItemBResponse: WithIdResponse {}
let subjectA: BehaviorSubject<ItemAResponse?> = BehaviorSubject(value: nil)
let subjectB: BehaviorSubject<ItemBResponse?> = BehaviorSubject(value: nil)
let singleA = subjectA.asSingle().id() // HERE WE HAVE ERROR
你要求元素是一个
Optional<any WithIdResponse>
。你需要你的通用类型来允许任何WithIdResponse
.的实现
这里是你如何做到的:
extension PrimitiveSequence where Trait == SingleTrait {
func id<Wrapped>() -> Single<String?> where Element == Optional<Wrapped>, Wrapped: WithIdResponse {
self.map { $0?.id }
}
}
顺便说一句,你知道 Swift 库中已经有一个
Identifiable
类型吗?我建议你使用它而不是自己制作。
像这样的东西:
extension PrimitiveSequence where Trait == SingleTrait {
func id<Wrapped>() -> Single<Wrapped.ID?> where Element == Optional<Wrapped>, Wrapped: Identifiable {
self.map { $0?.id }
}
}
struct ItemAResponse: Identifiable {
let id: String
}
let subjectA: BehaviorSubject<ItemAResponse?> = BehaviorSubject(value: nil)
let singleA = subjectA.asSingle().id() // This is a `PrimitiveSequence<SingleTrait, String?>`