你能解释/解决这些通用约束'编译错误?

时间:2017-09-26 18:41:58

标签: swift generics swift3 protocols

尝试使用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
    }
}

1 个答案:

答案 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变成更具体的结构并摆脱协议。但对于这样一个简单的案例,我通常会通过这个函数。