Scala:Is hashCode()&;仅在非平凡超类中尚未指定的情况下生成的case类的equals()?

Scala:Is hashCode()&;仅在非平凡超类中尚未指定的情况下生成的case类的equals()?,scala,inheritance,Scala,Inheritance,我试图定义一个抽象类“Vertex”,这样它的所有子类的所有实例都由抽象字段“id”标识(在集合/映射/不同等中),即使这些子类是定义其他单独参数的不同case类。因此,我希望实现所有子类调用抽象超类中定义的hashCode()&equals()。换句话说,对于从“顶点”继承的case类,我想禁用Scala编译器为case类生成的自动覆盖 根据以下示例,如果案例类已经在非平凡超类中显式定义了这些函数,Scala编译器似乎不会为该案例类生成hashCode()&equals(): abstract

我试图定义一个抽象类“Vertex”,这样它的所有子类的所有实例都由抽象字段“id”标识(在集合/映射/不同等中),即使这些子类是定义其他单独参数的不同case类。因此,我希望实现所有子类调用抽象超类中定义的
hashCode()&equals()
。换句话说,对于从“顶点”继承的case类,我想禁用Scala编译器为case类生成的自动覆盖

根据以下示例,如果案例类已经在非平凡超类中显式定义了这些函数,Scala编译器似乎不会为该案例类生成
hashCode()&equals()

abstract class AbstractVertex {
  val id: String

  // identify only by id, ignoring any additional fields of case classes

  override def hashCode(): Int = id.hashCode
  override def equals(obj: scala.Any): Boolean = {
    obj match {
      case other: AbstractVertex => other.id == id
      case _ => false
    }
  }
}

case class VertexType1(id: String, data: String) extends AbstractVertex

case class VertexType2(id: String, data: String) extends AbstractVertex

case class VertexType3(id: String, data: String) { // NOT an AbstractVertex
  // manually provide our own hashCode and equals
  override def hashCode(): Int = id.hashCode
  override def equals(obj: scala.Any): Boolean = {
    obj match {
      case other: VertexType3 => other.id == id
      case _ => false
    }
  }
}

case class VertexType4(id: String, data: String) // NOT an AbstractVertex

object Playground extends App {
  // create several vertices, all of the same id
  val v1a = VertexType1("x", "some")
  val v1b = VertexType1("x", "other")
  val v2a = VertexType2("x", "some")
  val v2b = VertexType2("x", "other")
  val v3a = VertexType3("x", "some")
  val v3b = VertexType3("x", "other")
  val v4a = VertexType4("x", "some")
  val v4b = VertexType4("x", "other")
  val v4c = VertexType4("x", "some")

  println(Set(v1a, v1b, v2a, v2b).size) // gives 1
  println(Set(v1a, v1b).size) // gives 1
  println(Set(v2a, v2b).size) // gives 1
  println(Set(v3a, v3b).size) // gives 1
  println(Set(v4a, v4b, v4c).size) // gives 2

  println(v1a == v1b) // gives true
  println(v1a == v2a) // gives true
  println(v1a == v3a) // gives false
  println(v1a == v4a) // gives false
  println(v4a == v4b) // gives false
  println(v4a == v4c) // gives true
}
因此,行为符合预期。更重要的是,通过
scalac-Xprint:typer playder.scala | grep“hashCode”-c5
编译上述代码片段表明,
hashCode()
仅为
VertexType4
生成,并被视为是为
VertexType3
的明确定义,而
VertexType1
VertexType2
不生成这些代码,因此,它们返回到
AbstractVertex
中定义的
hashCode()
。类似于
equals()


因此,一切都按预期进行。然而,由于这是Scala编译器如何为case类生成
hashCode()&equals()
的一个相当微妙的细节,我想知道这种行为有多“稳定”。在不同的Scala版本之间经常会有很多变化,所以这在将来可能会中断。我能相信这种行为吗?例如,是否有明确规定此类行为的官方票据?

这是记录在案的行为。各国(强调地雷):

每个case类都隐式重写scala.AnyRef类的某些方法定义,除非在case类本身中已经给出了相同方法的定义,或者在与AnyRef不同的case类的某些基类中给出了相同方法的具体定义。特别是:

  • 方法equals:(Any)Boolean是结构相等,其中两个实例如果都属于所讨论的case类并且它们具有相等的(关于equals)构造函数参数(限于类的元素,即第一个参数部分),则它们是相等的

  • 方法hashCode:Int计算哈希代码。如果数据结构成员的hashCode方法将equal(关于equals)值映射为equal散列码,那么case类hashCode方法也会映射

  • 方法toString:String返回一个字符串表示形式,其中包含类及其元素的名称