一尘不染

字典如何在Swift中使用Equatable协议?

swift

为了解决这个问题,我一直在研究实现Hashable协议的自定义结构。我正在尝试查看等效运算符重载(==)被调用多少次,具体取决于填充时是否存在哈希冲突Dictionary

更新资料

@马特写了一个定制结构的更清洁的例子,实现了哈希的协议,并展示了如何经常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的示例中根本没有哈希冲突,但==仍在被调用。在我进行的其他强制进行哈希冲突的实验(请参阅此问题的编辑历史)中,==似乎被称为随机次数。

这里发生了什么?


阅读 262

收藏
2020-07-07

共1个答案

一尘不染

好吧,有你的答案:

https://bugs.swift.org/browse/SR-3330?focusedCommentId=19980&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-
tabpanel#comment-19980

实际情况:

  • 我们仅在插入一次哈希值。
  • 我们不使用散列来比较元素,仅使用==。仅当您存储哈希时,才使用哈希进行比较是合理的,但这意味着每个字典都需要更多的内存使用。需要评估的折衷方案。
  • 我们尝试在评估Dictionary是否适合该元素之前插入该元素。这是因为该元素可能已经在字典中,在这种情况下,我们不再需要任何容量。
  • 调整字典大小时,必须重新哈希所有内容,因为我们没有存储哈希值。

因此,您看到的是:

  • 搜索键的一个哈希
  • 一些==的(搜索空格)
  • 集合中每个元素的哈希值(调整大小)
  • 搜索键的一个哈希值(实际上完全是浪费的,但是考虑到它仅在O👎重新分配之后才发生,所以没什么大不了的)
  • 一些==的(在新缓冲区中搜索空间)

我们所有人都完全错了。他们根本不使用哈希( ==)来决定这是否是 唯一的 密钥。然后,在集合增长的情况下,进行第二轮呼叫。

2020-07-07