尝试使用associatedType
声明协议时出现以下两个编译器错误 - 不确定generic constraint
是什么。
protocol Listener {
associatedType ValueType
func call(_ binding:Binding<ValueType>, value:ValueType)
}
class Binding<T> {
var value:T?
var listeners:[Listener] = [] // error 1: Protocol 'Listener' can only be used as a generic constraint because it has Self or associated type requirements
func fire() {
listeners.forEach { $0.call(self,value:self.value) } // error 2: Member 'call' cannot be used on value of protocol type 'Listener'; use a generic constraint instead
}
}
答案 0 :(得分:10)
这是对协议的错误使用。协议相关类型由协议的实现者确定,而不是协议的用户。泛型由协议的用户确定。没有自动将协议包装到泛型中(该功能将被称为&#34;存在容器&#34;并且我们不知道它何时会到来)。
[Listener]
不是完整类型。什么是ValueType
?
对于这种特殊情况,协议没有理由。它只捕获一个功能。你应该只传递函数:
class Binding<T> {
var value: T?
var listeners:[(Binding<T>, T) -> ()] = []
func fire() {
if let value = value {
listeners.forEach { $0(self, value) }
}
}
init() {}
}
如果您真的需要协议,可以将其提升为类型橡皮(AnyListener
):
protocol Listener {
associatedtype ValueType
func call(_ binding:Binding<ValueType>, value:ValueType)
}
struct AnyListener<ValueType>: Listener {
let _call: (Binding<ValueType>, ValueType) -> ()
init<L: Listener>(_ listener: L) where L.ValueType == ValueType {
_call = listener.call
}
func call(_ binding: Binding<ValueType>, value: ValueType) {
_call(binding, value)
}
}
class Binding<T> {
var value:T?
var listeners: [AnyListener<T>] = []
func fire() {
if let value = value {
listeners.forEach { $0.call(self, value: value) }
}
}
}
let listener = ... some listener ....
binding.listeners.append(AnyListener(listener))
或者你可以将AnyListener
变成更具体的结构并摆脱协议。但对于这样一个简单的案例,我通常会通过这个函数。