首页 > 解决方案 > 从哈希值计算中省略一个属性

问题描述

有没有一种方法可以hash(into:)用来计算结构/类的哈希值,同时省略某些属性的使用?

IE

struct CacheItem: Codable, Hashable {
    let val1: Int
    let val2: Int
    let date: Date = Date()

    func hash(into hasher: inout Hasher) {
        hasher.combine(val1) // leave out date for computing hash value
        hasher.combine(val2)
    }
}

我希望这会奏效:

let cache = Set<CacheItem>()
let item1 = CacheItem(val1: 0, val2: 0)
let item2 = CacheItem(val1: 0, val2: 0)

cache.insert(item1)
assert(cache.contains(item2))

但是,它没有用。

标签: swift

解决方案


ASet是唯一对象的集合,相等性基于与 的比较==。相等的对象必须具有相同的哈希值,但不能相反:不同的对象可以具有相同的哈希值。(一个简单的例子:有 2 64 个可能的哈希值,但字符串是无限多的。所以必然有不同的字符串具有相同的哈希值。)

可散列的集合(如SetDictionary)在其实现中使用散列值(例如将不同的对象放入不同的“桶”),但它们从不单独使用散列值来确定相等性。

的默认实现==比较所有(存储的)属性是否相等。因此,在您的情况下,如果item1item2具有相同但不同val1,那么它们是不同的对象,即使它们具有相同的哈希值。val2date

如果您希望具有相同但不同的对象val1val2认为date是相等的,那么您必须==自己实现:

struct CacheItem: Codable, Hashable {
    // ...
    
    static func ==(lhs: CacheItem, rhs: CacheItem) -> Bool {
        return lhs.val1 == rhs.val1 && lhs.val2 == rhs.val2
    }
}

然后

var cache = Set<CacheItem>()
let item1 = CacheItem(val1: 0, val2: 0)
let item2 = CacheItem(val1: 0, val2: 0)

cache.insert(item1)
print(cache.contains(item2))

将始终打印true.


推荐阅读