我有少量存储在集合中的自定义类实例。我需要检查该集合中是否包含某个元素。匹配的条件必须是对象的 ID,而不是其内容。
为简化起见,假设一个具有整数 var 作为唯一属性的类,以及该类的两个不同实例,都持有数字 1。
直接比较这些实例应该返回 true,但是当对第一个实例的引用存储在集合中时,查询该集合是否包含对第二个实例的引用应该返回 false。
因此我使用对象的 ObjectIdentifier 来生成可散列协议所需的散列函数。
据我了解,Swift Set 的 .contains 方法首先使用哈希值,如果发生哈希冲突,则使用 equatable 方法作为备用方法。
但是在以下可以在操场上运行的代码中,我得到了随机结果:
class MyClass: Hashable {
var number: Int
init(_ number: Int) {
self.number = number
}
static func == (lhs: MyClass, rhs: MyClass) -> Bool {
return lhs.number == rhs.number
}
func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(self))
}
}
var mySet: Set<MyClass> = []
let number1 = MyClass(1)
let secondNumber1 = MyClass(1)
number1 == secondNumber1 // true: integer values are equal, so are the wrapping classes
number1 === secondNumber1 // false: two different instances
mySet.insert(number1)
mySet.contains(number1) // true
mySet.contains(secondNumber1) // should be false but randomly changes between runs
如果您在 XCode Playground 中运行上述代码并手动重新启动 Playground 执行,则每次运行的最后一行都会产生不同的结果。期望的行为是每次都得到“假”。
那么实现所描述的行为的正确方法是什么?