Swift:相等泛型类型的数组

Fra*_*cia 5 generics types generic-collections ios swift

我最近几天一直在与 Swift 上的泛型相关的一些问题作斗争,但我没有找到一种方法来弄清楚如何实现这一点:

  • 我有一个类class Store<S: State>,其中State有一个扩展 Equatable 的简单协议protocol State: Equatable
  • 我有一个类Logger,我想在其中存储一个数组Stores以跟踪它们的每个更改并将它们State与旧值进行比较,从而能够检查每次迭代中的更改。

为此,我需要在我的记录器类中存储一个Any Kind of Store数组 。当我尝试使用 a 时出现问题val storeArray = [Store<Any>],它不起作用,因为 Any 不是一种Equatable类型,我需要它们来扩展EquatableNSObject能够比较它们之间的状态。

可以在 Swift 中实现吗?或者找出另一种方法来比较 2 个项目而不用通用扩展Equatable协议?

如果您想检查实现:

状态 :

protocol State: Equatable {
}
Run Code Online (Sandbox Code Playgroud)

店铺 :

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")
    }
}
Run Code Online (Sandbox Code Playgroud)

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

但是当我尝试创建一个[Store]数组时,我检索到下一个错误: Protocol 'Store' can only be used as a generic constraint because it has Self or associated type requirements

dr_*_*rto 3

我想我现在明白你的问题了。这个解决方案怎么样:

您可以将自己的自定义相等性检查添加到协议中,而不是让State符合;Equatable这样你就可以将你的状态存储在一个数组(var states: [State])中。缺点是您不能使用泛型,而必须在代码中进行类型检查,就像过去的美好时光一样。

例如,该State协议的简单版本:

protocol State {
  func isEqualTo(_ other: State) -> Bool
}
Run Code Online (Sandbox Code Playgroud)

您的具体状态类型必须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
  }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以将状态存储在数组中,例如检查是否已包含新状态:

let states: [State] = [ State1(foo: "hi"), State2(bar: 42), State1(foo: "bye")]
let newState = State2(bar: 42)
let containsNewState = states.contains { $0.isEqualTo(newState )}
Run Code Online (Sandbox Code Playgroud)