5

我正在尝试为基于左右操作数标识的协议实现 Equatable 协议。换句话说:我如何为一个协议实现 Equatable 协议,以确定实现该协议的两个实例(在我的情况下iNetworkSubscriber)是否相同(相同的对象引用)。像那样(错误消息包含在下面的代码中):

protocol iNetworkSubscriber : Equatable {

    func onMessage(_ packet: NetworkPacket)

}

func ==(lhs: iNetworkSubscriber, rhs: iNetworkSubscriber) -> Bool {     // <- Protocol 'iNetworkSubscriber' can only be used as a generic constraint because it has Self or associated type requirements
    return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)               // <- Cannot invoke initializer for type 'ObjectIdentifier' with an argument list of type '(iNetworkSubscriber)'
}

...我还尝试了身份运算符本身:

func ==(lhs: iNetworkSubscriber, rhs: iNetworkSubscriber) -> Bool {     // <- Protocol 'iNetworkSubscriber' can only be used as a generic constraint because it has Self or associated type requirements
    return lhs === rhs                                                  // <- Binary operator '===' cannot be applied to two 'iNetworkSubscriber' operands
}

有人知道如何解决这个问题吗?

4

2 回答 2

3

这里有两个问题。第一个是您不能ObjectIdentifier在值类型上使用。因此,您必须声明此协议以要求引用(类)类型:

protocol NetworkSubscriber : class, Equatable {
    func onMessage(_ packet: NetworkPacket)
}

(请不要i在协议的开头添加小写字母。这在 Swift 中以多种方式令人困惑。)

然后,您不能将此协议用作类型。它描述了一种类型(因为它依赖于Selfvia Equatable)。所以接受它的函数必须是通用的。

func ==<T: NetworkSubscriber>(lhs: T, rhs: T) -> Bool {
    return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
}

鉴于它NetworkSubscriber必须是一个类,您应该非常仔细地询问您是否应该在这里使用继承而不是协议。具有关联类型的协议使用起来非常复杂,混合类和协议会产生更大的复杂性。如果您已经在使用类,则类继承要简单得多。

于 2018-01-18T15:18:00.283 回答
2

class身份比较仅对对象(类实例、协议)有意义。所以马上,你知道你需要class对你的协议进行约束:

protocol NetworkSubscriber: class, Equatable {
    func onMessage(_ packet: NetworkPacket)
}

一旦你这样做了,身份比较运算符就可用于(因为它们现在保证是对象)===的实例。我建议您直接使用,NetworkSubscriber而不是定义一个==that calls ,以明确表明您正在执行身份比较,而不是值比较:======

let ns1 = getNewNetworkSubscriber()
let ns2 = getNewNetworkSubscriber()
print(n1 === n2) // false
print(n1 === n1) // true
于 2018-01-18T15:29:59.213 回答