Tim*_*Tim 2 hash hashable swift
我有一个类在集合和字典中被大量使用。出于性能原因,此类Hashable以旧方式实现并缓存计算的哈希值:
let hashValue: Int
init(...) {
self.hashValue = ...
}
Run Code Online (Sandbox Code Playgroud)
在 Xcode 10.2 中,我看到一条警告,该警告hashValue已被弃用,并且很快将不再是协议要求。
令我困扰的是无论如何都无法缓存计算出的哈希值,因为hash(into:)不会返回任何内容。
func hash(into hasher: inout Hasher) {
hasher.combine(...)
}
Run Code Online (Sandbox Code Playgroud)
考虑以下游乐场中的示例
class Class: Hashable {
let param: Int
init(param: Int) {
self.param = param
}
static func ==(lhs: Class, rhs: Class) -> Bool {
return lhs.param == rhs.param
}
public func hash(into hasher: inout Hasher) {
print("in hash")
hasher.combine(param)
}
}
var dict = [Class: Int]()
let instance = Class(param: 1)
dict[instance] = 1
dict[instance] = 2
Run Code Online (Sandbox Code Playgroud)
你会看到以下日志
in hash
in hash
in hash
Run Code Online (Sandbox Code Playgroud)
我不知道为什么我们看到 3 个调用而不是 2 个,但我们确实看到了 =)。
因此,每次您使用相同的实例作为字典键或将此实例添加到集合中时,您都会收到一个新的hash(into:)调用。
在我的代码中,这样的开销非常昂贵。有人知道解决方法吗?
一种选择是创建您自己的Hasher,为其提供实例的“基本组件”,然后调用finalize()以获取Int可以缓存的哈希值。
例如:
class C : Hashable {
let param: Int
private lazy var cachedHashValue: Int = {
var hasher = Hasher()
hasher.combine(param)
// ... repeat for other "essential components"
return hasher.finalize()
}()
init(param: Int) {
self.param = param
}
static func ==(lhs: C, rhs: C) -> Bool {
return lhs.param == rhs.param
}
public func hash(into hasher: inout Hasher) {
hasher.combine(cachedHashValue)
}
}
Run Code Online (Sandbox Code Playgroud)
对此有几点需要注意:
cachedHashValue。显然,在存储单个的情况下,Int这不会那么有效,但对于更昂贵的实例,这很可能有助于提高性能。
| 归档时间: |
|
| 查看次数: |
488 次 |
| 最近记录: |