如何根据实现该协议的两个实例的身份为协议实现 Equatable 协议?
How to implement Equatable protocol for a protocol based on the identity of two instances that implement this protocol?
我正在尝试为基于左右操作数标识的协议实现 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
}
有人知道如何解决这个问题吗?
这里有两个问题。首先是您不能对值类型使用 ObjectIdentifier
。所以你必须声明这个协议需要引用(class)类型:
protocol NetworkSubscriber : class, Equatable {
func onMessage(_ packet: NetworkPacket)
}
(请不要在协议的开头添加小写字母 i
。这在 Swift 中的几个方面造成混淆。)
那么,您不能将此协议用作类型。它描述了一种类型(因为它通过 Equatable
依赖于 Self
)。所以接受它的函数必须是通用的。
func ==<T: NetworkSubscriber>(lhs: T, rhs: T) -> Bool {
return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
}
鉴于 NetworkSubscriber
必须是 class,您应该非常仔细地询问是否应该在此处使用继承而不是协议。具有关联类型的协议使用起来非常复杂,混合 classes 和协议会产生更多的复杂性。 Class 如果您已经在使用 classes,那么继承会简单得多。
身份比较只对对象有意义(类、class
协议的实例)。所以马上,您知道您需要对协议进行 class
约束:
protocol NetworkSubscriber: class, Equatable {
func onMessage(_ packet: NetworkPacket)
}
执行此操作后,身份比较运算符 ===
可用于 NetworkSubscriber
的实例(因为它们现在保证是对象)。我建议您直接使用 ===
,而不是定义调用 ===
的 ==
,以明确表示您正在执行身份比较,而不是值比较:
let ns1 = getNewNetworkSubscriber()
let ns2 = getNewNetworkSubscriber()
print(n1 === n2) // false
print(n1 === n1) // true
我正在尝试为基于左右操作数标识的协议实现 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
}
有人知道如何解决这个问题吗?
这里有两个问题。首先是您不能对值类型使用 ObjectIdentifier
。所以你必须声明这个协议需要引用(class)类型:
protocol NetworkSubscriber : class, Equatable {
func onMessage(_ packet: NetworkPacket)
}
(请不要在协议的开头添加小写字母 i
。这在 Swift 中的几个方面造成混淆。)
那么,您不能将此协议用作类型。它描述了一种类型(因为它通过 Equatable
依赖于 Self
)。所以接受它的函数必须是通用的。
func ==<T: NetworkSubscriber>(lhs: T, rhs: T) -> Bool {
return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
}
鉴于 NetworkSubscriber
必须是 class,您应该非常仔细地询问是否应该在此处使用继承而不是协议。具有关联类型的协议使用起来非常复杂,混合 classes 和协议会产生更多的复杂性。 Class 如果您已经在使用 classes,那么继承会简单得多。
身份比较只对对象有意义(类、class
协议的实例)。所以马上,您知道您需要对协议进行 class
约束:
protocol NetworkSubscriber: class, Equatable {
func onMessage(_ packet: NetworkPacket)
}
执行此操作后,身份比较运算符 ===
可用于 NetworkSubscriber
的实例(因为它们现在保证是对象)。我建议您直接使用 ===
,而不是定义调用 ===
的 ==
,以明确表示您正在执行身份比较,而不是值比较:
let ns1 = getNewNetworkSubscriber()
let ns2 = getNewNetworkSubscriber()
print(n1 === n2) // false
print(n1 === n1) // true