[英]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.