[英]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
明確定義,而VertexType1
和VertexType2
不生成這些,因此它們回退到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.