2010-09-30 18 views
15

Mire el siguiente código.Comportamiento de inicialización de Scala

trait MyTrait { val myVal : String } 

class MyClass extends MyTrait { val myVal = "Value" } 

class MyClass2(val myVal: String) extends MyTrait 

¿Por qué se diferencia el orden de inicialización en caso de MyClass y MyClass2? El constructor de MyClass será tan

MyClass() { 
    MyTrait$class.$init$(this); 
    myVal = value 
} 

El constructor de MyClass2 será

MyClass2(String myVal) { this.myVal = myVal; MyTrait$class.$init$(this) } 

Creo que el orden de inicialización debe ser lo más MyClass2 's constructor hace, el mismo en ambos casos.

Respuesta

23

Al final de la sección 5.1 de la Scala specification, se define lo siguiente:

Evaluación de plantillas. Considere una plantilla sc con mt 1 con mt n {stats}. Si esta es la plantilla de un rasgo (§5.3.3), entonces su evaluación mixin consiste en una evaluación de las estadísticas de secuencia de las estadísticas . Si esta no es una plantilla de un rasgo , entonces su evaluación consiste en los siguientes pasos.

  • En primer lugar, se evalúa el constructor superclass sc (§5.1.1).
  • Luego, todas las clases base en la linealización de la plantilla (§5.1.2) hasta en la superclase de la plantilla denotada por sc son mixin-evaluadas. La evaluación de Mixin ocurre en orden inverso en la linealización .
  • Finalmente, se evalúan las estadísticas de la secuencia de instrucciones.

Tenga en cuenta, sin embargo, que los parámetros del constructor puede ser utilizado por ningún constructor que le siguen. Por lo tanto, debe inicializarse antes que ellos. Esto se hace explícito en el extremo de la sección 5.1.1:

una evaluación de un constructor de invocación targs x.c. . . (argsn) consta de los pasos siguientes:

  • En primer lugar, el prefijo x se evalúa.
  • Luego, los argumentos args1,. . . , argsn se evalúan desde la izquierda hasta derecha.
  • Por último, la clase que se está construido se inicializa mediante la evaluación de la plantilla de la clase mencionada por c.

Esto no tienen ningún problema, pero tiene un problema con las estadísticas {} estaba ejecutando la última. La razón por la cual {stats} se ejecuta por último es que puede hacer referencia a los atributos de sus clases y rasgos antepasados, mientras que los antepasados ​​obviamente no tienen conocimiento sobre sus descendientes. Por lo tanto, los antepasados ​​deben inicializarse por completo antes de que se ejecute {stats}.

Por supuesto, es posible que do necesite la inicialización anticipada. Esto está cubierto por la sección 5.1.6: Primeras definiciones. Así es cómo lo escribiría:

class MyClass extends { val myVal = "Value" } with MyTrait 
+0

Finalmente, he visto la razón por la que Scala inicializa un objeto en ese orden. Gracias por la respuesta, Daniel. – Dmitry

Cuestiones relacionadas