繁体   English   中英

Swift 如何在通用 class 中使用通用协议

[英]Swift how to use generic protocol in generic class

我正在为 state 管理编写一个库。 它基本上是一个简化的观察者模式,只有一个观察者/听众。

现在我有这个并且效果很好:

public final class StateStore<S> {
  
  private var currentState: S
  
  public var listener: ((S) -> Void)? = nil
  
  public init(initialState: S) {
    currentState = initialState
  }
  
  func update(_ block: (inout S) -> Void) {
    var nextState = currentState // struct's copy on write
    block(&nextState)
    currentState = nextState
    listener?(currentState)
  }
  
}

但是,我想将其更改为协议而不是块。 就像是:

public protocol StateListener: AnyObject {
  associatedtype S
  func didUpdateState(_ state: S)
}

public final class StateStore<S> {
  ...
  public weak var listener: StateListener<S>? // <- how to deal with associate type 
  ... 
}

我不能这样做,因为在上面的S是关联类型,而不是泛型类型。 所以我得到错误说Cannot specialize non-generic type 'StateListener'

我看过这个但没有帮助: 在泛型类中使用泛型协议

S 不是 Swift 样式; 使用完整的单词是现代标准。

public protocol StateListener: AnyObject {
  associatedtype State
  func didUpdateState(_: State)
}

public final class StateStore<Listener: StateListener> {
  public weak var listener: Listener?
}

您无需手动考虑关联类型。 它是内置的,可作为嵌套类型访问:

  func ƒ(_: Listener.State) {

  }

关键是使用Listener类型而不是S类型参数化StateStore 然后可以将S定义为Listener.S的类型别名:

public final class StateStore<Listener: StateListener> {
    public typealias S = Listener.S

请注意,现在您不能拥有StateStore<StateListener>类型的变量,该变量可以存储具有不同实现StateListener StateStore StateStore<StateListener>类型并没有真正的意义,也有充分的理由

我想说,想把它变成一个协议是相当奇怪的。 如果要为(S) -> Void类型命名,请在StateStore中使用类型别名:

public typealias StateListener = ((S) -> Void)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM