2016-09-29 105 views
1

我的印象是Scala案例類的hashCode完全由其字段決定。因此,我認爲緩存hashCode對於不可變的case類是安全的。具有緩存hashCode的Scala案例類

好像我錯了:

case class Foo(s: String) { 
    override val hashCode: Int = super.hashCode() 
} 

val f1 = Foo("foo") 
val f2 = Foo("foo") 

println(f1.hashCode == f2.hashCode) // FALSE 

誰能解釋這是怎麼回事就在這裏,好嗎?

附錄 - 只爲了比較:

case class Bar(s: String) 

val b1 = Bar("bar") 
val b2 = Bar("bar") 

println(b1.hashCode == b2.hashCode) // TRUE 

回答

6

不知道有關這個價值,但是你可以內嵌的ScalaRuntime._hashCode實現:

case class Foo(s: String) { 
    override val hashCode: Int = scala.util.hashing.MurmurHash3.productHash(this) 
} 
+0

是的,這是一個很好的解決方案:與基於公共API的實現一樣,行爲好像沒有被覆蓋(即僅基於字段的散列),但是被記憶 - 謝謝! – netzwerg

0

的情況下類實例的toString是完全依賴於它的領域不hashCode

+0

好吧,如果'hashCode'沒有被覆蓋 - 請參閱我的附錄 – netzwerg

1

不知道你的意思是「緩存hasCode」,但。 .. 您已覆蓋hashCode與從Object建立的自定義解決方案,這就是爲什麼你得到false。刪除這個覆蓋,你會得到預期的價值。

+0

我想記憶不可變case類的hashCode。但你現在就應該使用'override def hashCode():Int = ScalaRunTime._hashCode(this)'而不是'super.hashCode()'!這不是公共API,但...謝謝! – netzwerg

1

@ Rumoku的答案似乎變得什麼是真正回事。當你聲明case class Foo它編譯成這個:case class Foo extends AnyRef with Product with Serializable(見scalac-Xprint:typer選項)。另外,hashCode的實現也生成如下:override def hashCode: Int = scala.runtime.ScalaRunTime._hashCode(this)。但是,如果自己覆蓋hashCode,則不會生成此實施。關鍵是ProductSerializable都不實現hashCode,所以當您撥打super.hashCode時您正在執行的實現是AnyRef/Any/Object的默認實現。