Ho letto che il costrutto Scala'a case class
genera automaticamente un'implementazione equals
e hashCode
. Come si presenta esattamente il codice generato?hashCode nelle classi case in Scala
risposta
Come diceva il mio professore, solo il codice dice la verità! Quindi, basta dare un'occhiata al codice che viene generato per:
case class A(i: Int, s: String)
Siamo in grado di istruire il compilatore Scala per mostrarci il codice generato dopo le varie fasi, qui dopo coontrollore dei tipo:
% scalac -Xprint:typer test.scala
[[syntax trees at end of typer]]// Scala source: test.scala
package <empty> {
@serializable case class A extends java.lang.Object with ScalaObject with Product {
..
override def hashCode(): Int = ScalaRunTime.this._hashCode(A.this);
...
override def equals(x$1: Any): Boolean = A.this.eq(x$1).||(x$1 match {
case (i: Int,s: String)A((i$1 @ _), (s$1 @ _)) if i$1.==(i).&&(s$1.==(s)) => x$1.asInstanceOf[A].canEqual(A.this)
case _ => false
});
override def canEqual(x$1: Any): Boolean = x$1.$isInstanceOf[A]()
};
}
Così è possibile vedere che il calcolo del codice hash è delegato a ScalaRunTime._hashCode e l'uguaglianza dipende dall'uguaglianza dei membri della classe case.
Questo non solo lo spiega bene, ma mi ha insegnato su '-Xprint: typer'. Molte grazie! L'unica cosa di cui sono confuso è cosa significa "ScalaRunTime.this"? Perché non semplicemente 'ScalaRunTime._hashCode'? –
La sintassi 'ClassName.this' viene in genere utilizzata per accedere a un' this' esterno da una classe interna (che è la stessa di Java). Non sono sicuro del motivo per cui è stampato qui, forse è solo il modo in cui il codice è stampato dal compilatore. Ma questa è solo una supposizione, qualcun altro? –
Il generato hashCode
solo chiamate scala.runtime.ScalaRunTime._hashCode
, che è definito come:
def _hashCode(x: Product): Int = {
val arr = x.productArity
var code = arr
var i = 0
while (i < arr) {
val elem = x.productElement(i)
code = code * 41 + (if (elem == null) 0 else elem.hashCode())
i += 1
}
code
}
Quindi, quello che si ottiene è elem1 * 41**n + elem2 * 41**(n-1) .. elemn * 1
, dove n
è l'arietà della classe caso e elemi
sono i membri di quella classe caso.
Grazie per la risposta chiara. Ora non so se dovrei accettare la tua risposta o la risposta di Mirko, dalla quale ho anche imparato il pratico trucco '-Xprint: typer' ... –
Insieme, entrambe le risposte stanno rispondendo perfettamente alla domanda :-) –
Si prega di essere consapevoli del fatto che le risposte precedenti su questa domanda sono un po 'obsolete sulla parte hashCode.
Come di Scala 2.9 hashCode
per classi case usi MurmurHash
: link.
MurmurHash produces good avalanche effect, good distribution and is CPU friendly.
Sembra che le cose siano cambiate; usando l'esempio di Mirko case class A(i: Int, s: String)
ottengo: [? Qual è il codice generato per un metodo equals/hashCode di una classe case]
override <synthetic> def hashCode(): Int = {
<synthetic> var acc: Int = -889275714;
acc = scala.runtime.Statics.mix(acc, i);
acc = scala.runtime.Statics.mix(acc, scala.runtime.Statics.anyHash(s));
scala.runtime.Statics.finalizeHash(acc, 2)
};
e
override <synthetic> def equals(x$1: Any): Boolean = A.this.eq(x$1.asInstanceOf[Object]).||(x$1 match {
case (_: A) => true
case _ => false
}.&&({
<synthetic> val A$1: A = x$1.asInstanceOf[A];
A.this.i.==(A$1.i).&&(A.this.s.==(A$1.s)).&&(A$1.canEqual(A.this))
}))
};
possibile duplicato (http://stackoverflow.com/ domande/4526706/what-code-is-generated-for-an-equals-hashcode-method-of-a-case-class) – Suma