为了解决这个问题,我一直在研究实现Hashable协议的自定义结构。我正在尝试查看等效运算符重载(==)被调用多少次,具体取决于填充时是否存在哈希冲突Dictionary。
==
Dictionary
更新资料
@马特写了一个定制结构的更清洁的例子,实现了哈希的协议,并展示了如何经常hashValue和==调用。我在下面复制他的代码。要查看我的原始示例,请查看编辑历史记录。
hashValue
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的示例中根本没有哈希冲突,但==仍在被调用。在我进行的其他强制进行哈希冲突的实验(请参阅此问题的编辑历史)中,==似乎被称为随机次数。
func ==()
这里发生了什么?
好吧,有你的答案:
https://bugs.swift.org/browse/SR-3330?focusedCommentId=19980&page=com.atlassian.jira.plugin.system.issuetabpanels:comment- tabpanel#comment-19980
实际情况: 我们仅在插入一次哈希值。 我们不使用散列来比较元素,仅使用==。仅当您存储哈希时,才使用哈希进行比较是合理的,但这意味着每个字典都需要更多的内存使用。需要评估的折衷方案。 我们尝试在评估Dictionary是否适合该元素之前插入该元素。这是因为该元素可能已经在字典中,在这种情况下,我们不再需要任何容量。 调整字典大小时,必须重新哈希所有内容,因为我们没有存储哈希值。 因此,您看到的是: 搜索键的一个哈希 一些==的(搜索空格) 集合中每个元素的哈希值(调整大小) 搜索键的一个哈希值(实际上完全是浪费的,但是考虑到它仅在O👎重新分配之后才发生,所以没什么大不了的) 一些==的(在新缓冲区中搜索空间)
实际情况:
因此,您看到的是:
我们所有人都完全错了。他们根本不使用哈希( 仅 ==)来决定这是否是 唯一的 密钥。然后,在集合增长的情况下,进行第二轮呼叫。