scala - scala.Equals trait 中的 canEqual()

标签 scala internals scala-2.11

来自源码scala/Equals.scala ( here ):

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

在文档中,它说:

A method that should be called from every well-designed equals method that is open to be overridden in a subclass.



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

不幸的是,似乎是因为scala.Tuple2是一个案例类,canEqual()equals()方法是自动生成的,因此在源代码中找不到 scala/Tuple2.scala ( here )。

我的问题是:
  • 什么时候是扩展特征的好时机 scala.Equals ?
  • 应该怎么做canEqual()被执行?
  • 使用的最佳实践(或样板)是什么 canEqual()equals() ?

  • 提前致谢!

    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!
    

    要解决此问题,请使用 canEqual 确保两个实体属于相同(子)类型。在equals的定义中:
    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
    

    关于scala - scala.Equals trait 中的 canEqual(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32093526/

    相关文章:

    scala - 为什么这个Iterable在映射后会产生一个Set?

    Scala:从 mixin 类型别名继承时为 "class type required but {trait} with {trait} found"

    r - R中的内部字符串缓存

    Scala 解析器削减最后一个括号

    Scala 从 String 类名实例化对象

    java - 将 Sonar、Jacoco、Gradle、ScalaTest 与 Junit、Java 集成

    arrays - 在 Scala 中获取数组元素仅适用于显式应用方法

    git - Git 的包文件是增量而不是快照吗?

    c# - 使用 InternalsVisibleToAttribute 的单元测试需要使用/不使用 :filename. ext 进行编译?

    scala - 如何导入隐式对象?