Swift:具有Equatable通用类型的数组

5

我最近几天一直在处理Swift中有关泛型的问题,但我找不到解决方法来实现以下内容:

  • 我有一个类class Store<S: State>,其中State是一个简单的协议,它扩展了Equatableprotocol State: Equatable
  • 我有一个类Logger,我想存储一个Stores数组,以跟踪每个更改并比较它们的State与旧值,能够检查每个迭代中发生了什么更改。

为此,我需要在我的日志记录器类中存储任何类型的Store数组。当我尝试使用val storeArray = [Store<Any>]时,问题出现了,因为Any不是Equatable类型,我将需要让它们扩展EquatableNSObject以能够在它们之间比较状态。

在Swift中是否可能实现这一点?或者找到另一种方法来比较2个项目而不使泛型扩展Equatable协议?

如果您想要查看实现:

State:

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] 数组时,会出现以下错误:协议 'Store' 只能用作泛型约束,因为它具有 Self 或关联类型的要求


2
考虑使用具有关联类型的协议,而不是限制在协议上的泛型。 - vadian
你是否在数组中保存了不同的State类型(例如storeArray = [Store<State1>(), Store<State2>()])?如果是这样,那么Equatable无论如何都不起作用,因为它要求两个比较的对象是相同类型的(或多或少)。 - dr_barto
@vadian 我已经尝试使用一个协议来定义 Store,但是当我尝试使用该类型的数组时,我收到了以下错误提示:Protocol 'Store' can only be used as a generic constraint because it has Self or associated type requirements - Francisco Durdin Garcia
这是个好主意 @dr_barto,但我只想比较同类型的StoresStates,但我需要通用数组来迭代,有什么想法吗? - Francisco Durdin Garcia
1个回答

3
我想我现在理解了你的问题。这个解决方案怎么样:
不要让 `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 { $0.isEqualTo(newState )}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接