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
要求 ==
的实现完全基于被比较实例的可见方面(即 属性 值)。
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
键(比较 )。
我们有多个自定义 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 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
要求 ==
的实现完全基于被比较实例的可见方面(即 属性 值)。
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 anEquatable
type.
因此,使用 ==
对您的 class 进行身份比较从来都不正确,即使它最初可能有效。
至于什么时候应该使用 ObjectIdentifier
,实际上你永远不需要它 只是 来执行身份比较。对于 classes,你应该使用 ===
运算符,对于元类型,你应该简单地使用专门为它们定义的 ==
重载(在那种情况下,身份恰好等于相等,因为每个新的元类型实例都是唯一的)。
ObjectIdentifier
的主要用途实际上是它的 hashValue
实现,它派生自它初始化的对象的指针值。这可能很有用,例如,允许元类型成为 Dictionary
键(比较