Swift 平等需要 ObjectIdentifier?

ObjectIdentifier needed for Swift equality?

我们有多个自定义 Swift class 的实例,它继承自 SKSpriteNode,并且能够正确执行以下代码(针对此问题进行了粗略简化):

let instance1 = CustomClass()
let instance2 = CustomClass()
let instance3 = CustomClass()
let instance4 = CustomClass()

let array1 = [instance1, instance2]
let array2 = [instance3, instance4]

func check(testInstance: CustomClass) -> Bool {
   return array1.filter({ [=11=] == testInstance }).count > 0
}

check(testInstance: instance3)

换句话说,执行 check(testInstance: instance3) 按预期返回 false

但是,我们进行了一系列更改,check 停止工作。

CustomClass 没有实现 Equatable 协议。我们只想检测独特的实例。

在我们使用ObjectIdentifier的时候才开始工作,也就是说函数变成了这样:

func check(testInstance: CustomClass) -> Bool {
   return array1.filter({ ObjectIdentifier([=12=]) == ObjectIdentifier(testInstance) }).count > 0
}

为什么需要 ObjectIdentifier,什么时候应该用于对象相等?

这是用 Swift 3.

写的

Why is ObjectIdentifier needed, and when should it be used for object equality?

在这种情况下您不需要使用ObjectIdentifier来执行身份比较,您可以简单地使用身份运算符=== instead which, as ,因为class实例是等价的使用 ObjectIdentifier== 重载:

func check(testInstance: CustomClass) -> Bool {
    return array1.contains(where: { [=10=] === testInstance })
}

另请注意,我们在 filter{...}.count > 0 上使用 contains(where:),因为前者会在找到匹配元素时短路,而后者会评估整个序列(并创建一个不必要的中间数组).

直接使用 == 执行对象的身份比较 可能 有效,因为 CustomClass 最终继承自 NSObject,它通过定义 an == overload that calls isEqual(_:) 来符合 Equatable,它默认执行身份比较。

但是一般来说,这应该被依赖——isEqual(_:)的实现可以被覆盖以执行基于属性值的比较而不是比身份。此外,在语义上 Equatable 要求 == 的实现完全基于被比较实例的可见方面(即 属性 值)。

来自 the documentation:

Equality implies substitutability — any two instances that compare equally can be used interchangeably in any code that depends on their values. To maintain substitutability, the == operator should take into account all visible aspects of an Equatable type.

因此,使用 == 对您的 class 进行身份比较从来都不正确,即使它最初可能有效。

至于什么时候应该使用 ObjectIdentifier,实际上你永远不需要它 只是 来执行身份比较。对于 classes,你应该使用 === 运算符,对于元类型,你应该简单地使用专门为它们定义的 == 重载(在那种情况下,身份恰好等于相等,因为每个新的元类型实例都是唯一的)。

ObjectIdentifier 的主要用途实际上是它的 hashValue 实现,它派生自它初始化的对象的指针值。这可能很有用,例如,允许元类型成为 Dictionary 键(比较 )。