在 equals 方法中的 Scala 匹配

Scala match in equals method

我是 Scala 的新手,但有不错的 Java 背景。我的问题是关于重写 Scala 中的 equals 方法。以下示例来自 Scala 说明书:

class Person (name: String, age: Int) {
    def canEqual(a: Any) = a.isInstanceOf[Person]
    override def equals(that: Any): Boolean =
        that match {
            case that: Person => that.canEqual(this) && this.hashCode == that.hashCode
            case _ => false
     }
}

我的问题是为什么我们需要

that.canEqual(this)

我的理解是只有当 'that' 是一个人时才会执行该代码。那么,为什么要额外调用 isInstanceOf?

that.canEqual(this) 不是多余的。如果 thatPerson 的子类的实例,并且定义了它自己的相等性(并且它自己的 canEqual 方法),则这是必要的。

另一方面,

this.canEqual(that) 是多余的。

主要目的是确保Person的实例和Person的潜在子类之间的双向相等关系有效可能有自己的 equals 实现。

假设我有:

 class Person(...) {
    ... as defined, but without the `that.canEqual(this)` call
 }

 class Nobody extends Person {
   // contrived, but valid definition
   override def equals (that: Any) = false 
   ... and some definition of hashCode that happens to produce same value
 }

 ...
 // then
 new Person(...) == new Nobody // true
 new Nobody == new Person(...) // false

 // breaks equals by not being symmetric

更详细的解释 link 由 pedrofurla 在评论中提供:http://www.artima.com/pins1ed/object-equality.html

来自两个不同 类 的两个不同对象可以具有相同的哈希码;因此,您不能仅根据哈希码就说两个对象相等。例如,由于 Dog 定义 hashCode 的方式,具有黄色皮毛和响亮树皮的 Dog 可能具有 20011 年的 hashCodeRocketShip 设计用于飞往土星的 hashCode 也可能出于非常不相关的原因而具有 20011 年的 hashCode。显然,这是两个截然不同的对象。但是,如果两个 Dogs 或两个 RocketShips 具有相同的哈希码,那么可以*安全地假设它们是等效对象:必须具有两个等效对象是没有任何意义的(例如,两个 Dogs 有黄色皮毛和响亮的吠声)有两个不同的哈希码,并且拥有两个相同类型的不同对象(例如,一个 Dog 有黑色皮毛)是没有意义的,另一个有棕色毛皮的)具有相同的哈希码。 isInstanceOf 检查可确保您处理的是同一类型的两个对象:哈希码检查可让您快速评估两个对象 是否应该 相同.

(*: 如果有有限个哈希码和无限个属性组合产生唯一Dogs,那么不可避免地会发生哈希码冲突。即使isInstanceOf检查也是'不够,但对于大多数情况来说可能已经足够了,因此在食谱中就是一个例子。)

编辑: 参见 here

Pitfall #2: Changing equals without also changing hashCode. If two objects are equal according to the equals method, then calling the hashCode method on each of the two objects must produce the same integer result

简而言之,两个相等的对象必须具有相同的哈希码才能履行方法的合同(但没有任何地方说具有相同哈希码的两个对象必须相等!)

编辑 2 由于您有 Java 背景,您可能已经习惯看到以下内容。

public boolean equals(Object other) {

   // I am a Dog. If they're not a dog, I can't be equal to them.
   if (!(other instanceof Dog)) 
      return false;

   // If the other dog's properties are equal to my own, then we're equal.
   if (...)
      return true;
   // If not, we're not equal.
   else
      return false;
 }

您给出的代码示例正在做(大致)相同的事情,用 hashCode 检查代替相等检查。