2011-05-03 5 views
49

He leído que la construcción de Scala'a case class genera automáticamente una implementación de montaje equals y hashCode. ¿A qué se parece exactamente el código generado?hashCode en las clases de caso en Scala

+1

posible duplicado de (http://stackoverflow.com/ preguntas/4526706/what-code-is-generated-for-an-equals-hashcode-method-of-a-case-class) – Suma

Respuesta

67

Como solía decir mi profesor, ¡solo el código dice la verdad! Así que sólo echar un vistazo al código que se genera para:

case class A(i: Int, s: String) 

Podemos dar instrucciones al compilador de Scala para mostrarnos el código generado después de las diferentes fases, aquí después de la typechecker:

% 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]() 
    }; 
} 

por lo Puede ver que el cálculo del código hash está delegado en ScalaRunTime._hashCode y la igualdad depende de la igualdad de los miembros de la clase de caso.

+4

Esto no solo lo explica bien, sino que me enseñó sobre '-Xprint: typer'. ¡Muchas gracias! Lo único que estoy confundido es ¿qué significa 'ScalaRunTime.this'? ¿Por qué no simplemente 'ScalaRunTime._hashCode'? –

+0

La sintaxis 'ClassName.this' se usa generalmente para acceder a un' this' externo desde dentro de una clase interna (es lo mismo que en Java). No estoy seguro de por qué está impreso aquí, tal vez es la forma en que el código está bastante impreso por el compilador. Pero eso es solo una suposición, ¿alguien más? –

46

El generada hashCode sólo llama scala.runtime.ScalaRunTime._hashCode, que se define como:

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 
} 

Así que lo que se obtiene es elem1 * 41**n + elem2 * 41**(n-1) .. elemn * 1, donde n es la aridad de su clase de caso y elemi son los miembros de esa clase caso.

+0

Gracias por la respuesta clara. Ahora no sé si debería aceptar su respuesta o la respuesta de Mirko, de la cual también aprendí el práctico truco '-Xprint: typer' ... –

+0

Juntas, ambas respuestas responden perfectamente a la pregunta :-) –

0

Parece que las cosas han cambiado; usando el ejemplo de Mirko case class A(i: Int, s: String) me sale: [? ¿Qué código se genera para un método equals/hashCode de una clase caso]

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) 
    }; 

y

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)) 
    })) 
    }; 
Cuestiones relacionadas