Swift哈希(到:)可哈希协议要求的缓存结果
我有一门课被大量地用在集合和字典中。 出于性能原因,此类以旧的方式实现Hashable并缓存计算的哈希:Swift哈希(到:)可哈希协议要求的缓存结果,swift,hash,hashable,Swift,Hash,Hashable,我有一门课被大量地用在集合和字典中。 出于性能原因,此类以旧的方式实现Hashable并缓存计算的哈希: let hashValue: Int init(...) { self.hashValue = ... } 在Xcode 10.2中,我看到一个警告,hashValue已被弃用,不久将不再是协议要求 困扰我的是,无论如何都无法缓存计算出的哈希,因为hashinto:不返回任何内容 func hash(into hasher: inout Hasher) { hasher.
let hashValue: Int
init(...) {
self.hashValue = ...
}
在Xcode 10.2中,我看到一个警告,hashValue已被弃用,不久将不再是协议要求
困扰我的是,无论如何都无法缓存计算出的哈希,因为hashinto:不返回任何内容
func hash(into hasher: inout Hasher) {
hasher.combine(...)
}
考虑以下在操场上的例子
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
您将看到以下日志
in hash
in hash
in hash
我不知道,为什么我们看到的是3个呼叫而不是2个,但我们看到的是=
因此,每次使用同一实例作为字典键或将该实例添加到集合中时,都会得到一个新的hashinto:call
在我的代码中,这样的开销是非常昂贵的。有人知道一种解决方法吗?一种方法是创建自己的哈希程序,将实例的基本组件提供给它,然后调用它以获取可以缓存的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)
}
}
关于这一点,需要注意以下几点:
它依赖于您的基本组件是不可变的,否则一个新的哈希值将需要在变异时计算。
哈希值不能保证在程序执行期间保持稳定,所以不要序列化cachedHashValue。
显然,在存储单个Int的情况下,这并不是很有效,但对于更昂贵的实例,这很可能有助于提高性能。看起来像一个黑客=我会测量它并稍后共享一个报告=鉴于Hasher应该如何使用,我不会真的称它为黑客。我承认这比使用hashValue要复杂一些,但是,正如Martin所说,新的API允许更健壮的hash值。