2016-09-29 138 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的默认实现。