繁体   English   中英

scala.Equals特征中的canEqual()

[英]canEqual() in the scala.Equals trait

从源代码scala/Equals.scala这里 ):

package scala
trait Equals extends scala.Any {
  def canEqual(that: scala.Any): scala.Boolean
  def equals(that: scala.Any): scala.Boolean
}

在文档中,它说:

应该从每个设计良好的equals方法调用的方法,该方法在子类中被重写。

我随机选择了一个扩展scala.Equals的类,这个类很容易理解。 我选择了scala.Tuple2[+T1, +T2] ,它扩展了特征scala.Product[T1, T2] ,后者又扩展了特征scala.Product ,后者又扩展了特征scala.Equals

不幸的是,似乎因为scala.Tuple2是一个case类 ,所以canEqual()equals()方法是自动生成的,因此无法在源代码scala/Tuple2.scala这里 )中找到。

我的问题是:

  • 什么时候是扩展特征scala.Equals的好时机?
  • canEqual()应该如何实现?
  • equals()使用canEqual()的最佳实践(或样板文件)是什么?

提前致谢!

PS:万一重要,我使用的是Scala 2.11.7。

canEquals方法用于覆盖equals应该是对称的期望 - 也就是说,如果(并且仅当) a.equals(b)为真,则b.equals(a)也应该为真。 将类的实例与子类的实例进行比较时,可能会出现问题。 例如。

class Animal(numLegs: Int, isCarnivore: Boolean) {
  def equals(other: Any) = other match {
    case that: Animal => 
      this.numLegs == that.numLegs && 
      this.isCarnivore == that.isCarnivore
    case _ => false
  }
}

class Dog(numLegs: Int, isCarnivore: Boolean, breed: String) extends Animal(numLegs, isCarnivore) {
  def equals(other: Any) = other match {
    case that: Dog => 
      this.numLegs == that.numLegs && 
      this.isCarnivore == that.isCarnivore &&
      this.breed == that.breed
    case _ => false
  }
}

val cecil = new Animal(4, true)
val bruce = new Dog(4, true, "Boxer")
cecil.equals(bruce) // true
bruce.equals(cecil) // false - cecil isn't a Dog!

要解决此问题,请在equals的定义中使用canEqual确保两个实体属于相同(子)类型:

class Animal(numLegs: Int, isCarnivore: Boolean) {
  def canEqual(other: Any) = other.isInstanceOf[Animal]
  def equals(other: Any) = other match {
    case that: Animal => 
      that.canEqual(this) &&
      this.numLegs == that.numLegs && 
      this.isCarnivore == that.isCarnivore
    case _ => false
  }
}

class Dog(numLegs: Int, isCarnivore: Boolean, breed: String) extends Animal(numLegs, isCarnivore) {
  def canEqual(other: Any) = other.isInstanceOf[Dog]
  def equals(other: Any) = other match {
    case that: Dog => 
      that.canEqual(this) &&
      this.numLegs == that.numLegs && 
      this.isCarnivore == that.isCarnivore &&
      this.breed == that.breed
    case _ => false
  }
}

val cecil = new Animal(4, true)
val bruce = new Dog(4, true, "Boxer")
cecil.equals(bruce) // false - call to bruce.canEqual(cecil) returns false
bruce.equals(cecil) // false

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM