【问题标题】:How `set.contains` works in Scala?`set.contains` 在 Scala 中是如何工作的?
【发布时间】:2021-01-19 22:03:43
【问题描述】:

考虑以下代码:

import scala.collection.mutable

case class A(b: Int) {
  override def equals(obj: Any): Boolean = {
    println("called")
    obj match {
      case o: A => b == o.b
      case _ => false
    }
  }
}

val set = mutable.Set.empty[A]
val a1 = A(1)
set.add(a1)
println(set.contains(A(1)))
println(set.contains(A(2)))

为什么set.contains 的第二次调用没有打印出“被调用”?有人能解释一下 set 如何识别两个相等的对象吗?

【问题讨论】:

  • 可变的SetHashSet 支持,因此它首先调用hashcode 来识别某个桶,然后使用equals 来比较桶的元素。这就是为什么hashcodeequals 必须始终保持一致,否则你会为这样的错误打开大门。 - 顺便说一句,在实践中,永远不要覆盖 case 类equals,如果您想要自定义等价性,请改用普通类。
  • @LuisMiguelMejíaSuárez 太好了!你能解释一下 Scala 中hashCode 的原始实现是什么,如果我只想查看一个类的属性子集来确定两个实例是否相等,我该如何覆盖它。
  • 搜索 "Effective Java hashcode and equals" - 请使用普通类,除非您希望为您的代码的未来合作者感到兴奋。另外,我建议选择不同的设计,例如将不属于相等性的字段移动到第二个参数列表或具有两个案例类。
  • @LuisMiguelMejíaSuárez 太好了!这完全解决了我的问题。您介意写一个简短的答案,以便我接受并结束这个问题吗?谢谢!

标签: scala set equals hashcode case-class


【解决方案1】:

正如 @LuisMiguelMejíaSuárez 在 cmets 中提到的,可变的 SetHashSet 支持。 What issues should be considered when overriding equals and hashCode in Java?

只要 a.equals(b),则 a.hashCode() 必须与 b.hashCode() 相同。

这是因为hashCode 是预先检查,如果失败equals 肯定也会失败。

What code is generated for an equals/hashCode method of a case class? 我们可以得出结论,对于案例类hashCodeequals 被覆盖,使用productPrefix,这意味着案例类中的第一组元素。例如,如果我们有:

case class c(a: A)(b: B)

hashCodeequals 将仅基于a 计算。在您的情况下,hasCode 方法是基于gender 计算的,这对于Person(1)Person(2) 是不同的。因此无需检查equals,它也假设失败。

来自What issues should be considered when overriding equals and hashCode in Java?的提示

在实践中:

如果你覆盖了一个,那么你应该覆盖另一个。

使用与计算 equals() 相同的一组字段来计算 hashCode()。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-07
    • 2017-07-04
    • 1970-01-01
    • 1970-01-01
    • 2017-03-03
    • 1970-01-01
    • 2013-02-12
    • 1970-01-01
    相关资源
    最近更新 更多