【发布时间】:2015-10-18 09:19:58
【问题描述】:
为了解决this question,我一直在玩一个实现哈希协议的自定义结构。我正在尝试查看等效运算符重载 (==) 的调用次数,具体取决于填充 Dictionary 时是否存在哈希冲突。
更新
@matt 编写了一个更简洁的自定义结构示例,该结构实现了 Hashable 协议,并显示了hashValue 和== 被调用的频率。我在下面复制his code。要查看我的原始示例,请查看edit history。
struct S : Hashable {
static func ==(lhs:S,rhs:S) -> Bool {
print("called == for", lhs.id, rhs.id)
return lhs.id == rhs.id
}
let id : Int
var hashValue : Int {
print("called hashValue for", self.id)
return self.id
}
init(_ id:Int) {self.id = id}
}
var s = Set<S>()
for i in 1...5 {
print("inserting", i)
s.insert(S(i))
}
这会产生结果:
/*
inserting 1
called hashValue for 1
inserting 2
called hashValue for 2
called == for 1 2
called hashValue for 1
called hashValue for 2
inserting 3
called hashValue for 3
inserting 4
called hashValue for 4
called == for 3 4
called == for 1 4
called hashValue for 2
called hashValue for 3
called hashValue for 1
called hashValue for 4
called == for 3 4
called == for 1 4
inserting 5
called hashValue for 5
*/
由于 Hashable 使用 Equatable 来区分散列冲突(我假设无论如何),我希望 func ==() 仅在存在散列冲突时被调用。但是,在上面的@matt 示例中根本没有散列冲突,但仍在调用==。在我的其他强制哈希冲突的实验中(请参阅此问题的编辑历史记录),== 似乎被称为随机次数。
这是怎么回事?
【问题讨论】:
-
我讨厌给出这个答案,甚至是评论,但这是一个 Swift 内部实现细节。他们可以根据需要优化类型,只要它符合文档中的 Dictionary API。并且这些文档不保证多久检查一次密钥是否相等——它们只要求您提供
==接口。我想我们会在今年晚些时候 Swift 开源时了解更多。另外,请参阅我对您的 other question 的类似评论。 -
这是一个更简单的测试(我认为):gist.github.com/mattneub/430fef70e3496f5ce6917aa35c98f419 输出非常明确地说明了每次插入调用
hashValue和==的次数。 -
@matt,是的,这是一个更简单、更清晰的测试。但现在我比我想象的更困惑。您的示例没有哈希冲突,对吗?然而
==仍然被调用。我之前的假设是==只被调用来处理哈希冲突情况。 -
是的,我也很惊讶。我正在考虑向 bugs.swift.org 提交错误报告,除非你愿意这样做——毕竟,这是你的主意,所以我不想窃取它。 (另外,我尝试阅读源代码,但无法弄清楚底层 VariantBuffer 的实现位置。所以我无法回答您的实际问题。)
标签: swift dictionary hash-collision hashable equatable