【问题标题】:Why aren't Swift classes hashable by default?为什么默认情况下 Swift 类不是可散列的?
【发布时间】:2017-06-05 21:44:25
【问题描述】:

类有一个标识,它们的 hashValue 很容易成为它们在内存中的地址。为什么不是这样?

【问题讨论】:

  • 我很确定一个对象的哈希/摘要应该基于它的内容,而不是它的身份或地址——如果一个对象具有“不相关”状态(例如缓存值),那么它不应该是哈希计算的一部分,但 Swift 编译器不知道这一点。如果哈希值基于对象的地址,那么使用内存碎片整理的运行时(如 CLR,它将在 GC 暂停期间移动内存中的对象)将与 Swift 根本不兼容。

标签: swift class


【解决方案1】:

因为基于身份的hashValue 根本不是很有用。

这是一个例子:

假设我正在合并来自两个不同来源的两组数据并检查重复项。一种常见的方法是将两者都添加到Set。这些对象肯定会有唯一的身份(即不同的地址)。如果这意味着它们也有唯一的hashValues,那么将不会检测到任何重复项。

使用Set 进行重复的全部原因首先是因为hashValue 暗示了重复的定义。你的提议会破坏这一点。

【讨论】:

  • 很抱歉,但我不明白为什么依赖对象身份并不谨慎?如果一个对象是在堆上分配的,它的指针实际上就是它的标识。假设这一点似乎是必要和合理的,不是吗?
  • 是的,一个对象的内存地址确实是它的标识。 (例如,这就是为什么比较引用的运算符(=== 被称为“相同的运算符”)。但我们在这里谈论的是不同的东西。让S 成为所有类型为@987654330 的实例的集合@. Swift 相等运算符(==)是一个equivalence relation(确实是最明显的例子),它可以用来将S 划分为equivalence classes
  • 当两个实例 ab 是同一个等价类的成员时,这由 a == b 返回 true 表示。如果cab 在不同的等价类中,则a == ca== c 都将返回false。通过将对象标识与对象相等性混为一谈,您实际上是将您的集合 S 划分为 |S|(意思是“S 的大小”)不同的分区,其中每个实例(每个对象)都是其等价类的唯一成员(因为它是唯一具有该引用的对象,并且每个其他引用都不同)。
  • 非常有用的两个有 2 个不同的实例(即不同的身份),它们比较相等。我想不出有什么情况可以保证没有两个不相同的对象必须比较为不相等。此外,如果你真的想要一个用于身份相等的运算符,你已经在=== 中找到了它。 == 有意作为一个单独的概念存在,一个将先前的等价类“合并”成新的大型等价类的运算符,每个新的大型等价类都有多个成员,它们共享一些特定的属性。
  • 说了这么多,我并没有真正谈论hashValue,因为平等是谈论这个的更简单的方式。 hashValue 只是平等的启发式。如果两个对象具有相同的 hashValues,则与其他任何对象(具有不同的 hashValues)相比,它们进行同等比较的可能性更高。当通过散列搜索集合中的对象时,散列允许您剔除集合的大部分,因此您无需对所有元素进行相等性检查。相反,您只需对具有相同 hashValues 的对象集进行相等性检查。
猜你喜欢
  • 1970-01-01
  • 2016-04-22
  • 2022-11-26
  • 1970-01-01
  • 2015-01-06
  • 2015-05-11
  • 2010-11-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多