簡體   English   中英

Scala:如果在非平凡超類中尚未指定的情況下,是否僅生成了案例類的hashCode()和equals()?

[英]Scala: Is hashCode() & equals() for case classes only generated if not already specified in a non-trivial superclass?

我嘗試定義一個抽象類“Vertex”,使得所有子類的所有實例都被抽象字段“id”標識(在sets / maps / distinct等中),即使子類是不同的case類定義其他單個參數。 因此,我想實現所有子類調用抽象超類中定義的hashCode() & equals() 換句話說,對於從“Vertex”繼承的case類,我想禁用Scala編譯器為case類生成的自動覆蓋。

根據以下示例,如果案例類已經在非平凡的超類中顯式定義了這些函數,則Scala編譯器似乎不會為case類生成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 Playground.scala | grep "hashCode" -C 5編譯上面的代碼片段 scalac -Xprint:typer Playground.scala | grep "hashCode" -C 5表示hashCode()僅為VertexType4生成,並且視為為VertexType3明確定義,而VertexType1VertexType2不生成這些,因此它們回退到AbstractVertex定義的hashCode() 類似於equals()

所以一切都按預期工作正常。 但是,由於這是Scala編譯器如何處理為case類生成hashCode() & equals()一個非常微妙的細節,我想知道這種行為是多么“穩定”。 不同的Scala版本之間經常會有很多變化,因此將來可能會中斷。 我可以依靠這種行為嗎? 例如,是否有一些正式票據,這種行為是明確指定的?

這是記錄在案的行為。 Scala規范的第5.3.2節 (強調我的):

每個case類隱式覆蓋scala.AnyRef類的一些方法定義, 除非在case類本身中已經給出了相同方法的定義,或者在不同於AnyRef的case類的某個基類中給出了相同方法的具體定義 尤其是:

  • 方法等於:(任意)布爾值是結構相等,其中兩個實例相等,如果它們都屬於所討論的案例類並且它們具有相等(相對於等於)構造函數參數(僅限於類的元素,即第一個參數)部分)。

  • 方法hashCode:Int計算哈希碼。 如果數據結構成員的hashCode方法映射相等(相對於equals)值為相等的哈希碼,那么case類hashCode方法也是如此。

  • 方法toString:String返回一個字符串表示形式,其中包含類及其元素的名稱。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM