Swift: 等值泛型数组
Swift: Array of equatable generic type
最近几天我一直在与 Swift 上的泛型相关的一些问题作斗争,但我没有找到解决方法:
- 我有一个 class
class Store<S: State>
其中 State
是一个扩展 Equatable protocol State: Equatable
. 的简单协议
- 我有一个 class
Logger
,我想在其中存储一个 Stores
的数组,以跟踪它们的每个更改并将它们的 State
与旧的进行比较值,能够检查每次迭代中的变化。
为此,我需要在我的记录器 class 中存储一个 任何类型的商店 的数组。当我尝试使用 val storeArray = [Store<Any>]
时出现问题,它不起作用,因为 Any 不是 Equatable
类型,我需要它们扩展 Equatable
或 NSObject
能够比较它们之间的状态。
可以在 Swift 中实现吗?或者找出另一种方法来比较 2 个项目而不使通用扩展 Equatable
协议?
如果您想检查实施情况:
状态:
protocol State: Equatable {
}
商店:
class Store<S: State> {
private var _initialState: S
private var _state: S
private var processor = PublishSubject<S>()
init(initialState: S) {
_initialState = initialState
_state = initialState
}
var state: S {
get {
return _state
}
set(value) {
if (value != state) {
_state = value
processor.onNext(value)
}
}
}
func initialState() -> S {
return _initialState
}
/// Initialize the store. Called after all stores instances are ready.
func initialize() {
//TODO Check if its possible to force an override over a method
preconditionFailure("This method must be overridden")
}
}
根据 Vadian 的建议,我尝试将其移动到具有关联类型的协议:
protocol Store: class {
associatedtype State : StateDelegate
var processor : PublishSubject<State> { get }
var _state : State { get set }
var state: State { get set }
func initialState() -> State
func flowable() -> Observable<State>
func initialize() -> Void
}
extension Store {
var state: State {
get {
return _state
}
set(value) {
if (value != state) {
_state = value
processor.onNext(value)
}
}
}
func flowable() -> Observable<State> {
return processor.startWith(state)
}
func initialState() -> State {
return State.init()
}
}
但是当我尝试创建一个 [Store]
数组时,我检索到下一个错误:
Protocol 'Store' can only be used as a generic constraint because it has Self or associated type requirements
我想我现在明白你的问题了。这个解决方案怎么样:
不是让 State
符合 Equatable
,而是将您自己的自定义相等性检查添加到协议;这样你就可以将你的状态存储在一个数组中(var states: [State]
)。缺点是你不能使用泛型,而是必须在代码中进行类型检查,就像过去的美好时光一样。
例如,State
协议的简单版本:
protocol State {
func isEqualTo(_ other: State) -> Bool
}
您的具体状态类型必须实现 isEqualTo
并在测试相等性之前执行类型检查:
struct State1: State {
var foo: String
func isEqualTo(_ other: State) -> Bool {
guard let state1 = other as? State1 else { return false }
return self.foo == state1.foo
}
}
现在您可以将状态存储在数组中,例如检查是否已包含新状态:
let states: [State] = [ State1(foo: "hi"), State2(bar: 42), State1(foo: "bye")]
let newState = State2(bar: 42)
let containsNewState = states.contains { [=12=].isEqualTo(newState )}
最近几天我一直在与 Swift 上的泛型相关的一些问题作斗争,但我没有找到解决方法:
- 我有一个 class
class Store<S: State>
其中State
是一个扩展 Equatableprotocol State: Equatable
. 的简单协议
- 我有一个 class
Logger
,我想在其中存储一个Stores
的数组,以跟踪它们的每个更改并将它们的State
与旧的进行比较值,能够检查每次迭代中的变化。
为此,我需要在我的记录器 class 中存储一个 任何类型的商店 的数组。当我尝试使用 val storeArray = [Store<Any>]
时出现问题,它不起作用,因为 Any 不是 Equatable
类型,我需要它们扩展 Equatable
或 NSObject
能够比较它们之间的状态。
可以在 Swift 中实现吗?或者找出另一种方法来比较 2 个项目而不使通用扩展 Equatable
协议?
如果您想检查实施情况:
状态:
protocol State: Equatable {
}
商店:
class Store<S: State> {
private var _initialState: S
private var _state: S
private var processor = PublishSubject<S>()
init(initialState: S) {
_initialState = initialState
_state = initialState
}
var state: S {
get {
return _state
}
set(value) {
if (value != state) {
_state = value
processor.onNext(value)
}
}
}
func initialState() -> S {
return _initialState
}
/// Initialize the store. Called after all stores instances are ready.
func initialize() {
//TODO Check if its possible to force an override over a method
preconditionFailure("This method must be overridden")
}
}
根据 Vadian 的建议,我尝试将其移动到具有关联类型的协议:
protocol Store: class {
associatedtype State : StateDelegate
var processor : PublishSubject<State> { get }
var _state : State { get set }
var state: State { get set }
func initialState() -> State
func flowable() -> Observable<State>
func initialize() -> Void
}
extension Store {
var state: State {
get {
return _state
}
set(value) {
if (value != state) {
_state = value
processor.onNext(value)
}
}
}
func flowable() -> Observable<State> {
return processor.startWith(state)
}
func initialState() -> State {
return State.init()
}
}
但是当我尝试创建一个 [Store]
数组时,我检索到下一个错误:
Protocol 'Store' can only be used as a generic constraint because it has Self or associated type requirements
我想我现在明白你的问题了。这个解决方案怎么样:
不是让 State
符合 Equatable
,而是将您自己的自定义相等性检查添加到协议;这样你就可以将你的状态存储在一个数组中(var states: [State]
)。缺点是你不能使用泛型,而是必须在代码中进行类型检查,就像过去的美好时光一样。
例如,State
协议的简单版本:
protocol State {
func isEqualTo(_ other: State) -> Bool
}
您的具体状态类型必须实现 isEqualTo
并在测试相等性之前执行类型检查:
struct State1: State {
var foo: String
func isEqualTo(_ other: State) -> Bool {
guard let state1 = other as? State1 else { return false }
return self.foo == state1.foo
}
}
现在您可以将状态存储在数组中,例如检查是否已包含新状态:
let states: [State] = [ State1(foo: "hi"), State2(bar: 42), State1(foo: "bye")]
let newState = State2(bar: 42)
let containsNewState = states.contains { [=12=].isEqualTo(newState )}