Scala инициализация поведения - PullRequest
15 голосов
/ 30 сентября 2010

Пожалуйста, посмотрите на следующий код.

trait MyTrait { val myVal : String }

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

class MyClass2(val myVal: String) extends MyTrait 

Почему порядок инициализации отличается в случае MyClass и MyClass2? Конструктор MyClass будет иметь вид

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

Конструктор MyClass2 будет

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

Я думаю, что порядок инициализации должен быть таким же, как в конструкторе MyClass2, то же самое для обоих случаев.

1 Ответ

23 голосов
/ 30 сентября 2010

В конце раздела 5.1 спецификации Scala определено следующее:

Оценка шаблона. Рассмотрим шаблон sc с mt 1 с mt n {stats} .Если это шаблон признака (§5.3.3), то его смешанная оценка состоит из оценки статистики последовательности операторов.Если это не шаблон признака, то его оценка состоит из следующих шагов:

  • Сначала вычисляется конструктор суперкласса sc (§5.1.1).
  • Затемвсе базовые классы в линеаризации шаблона (§5.1.2) вплоть до суперкласса шаблона, обозначенного sc, подвергаются смешанной оценке.Смешанная оценка происходит в обратном порядке вхождения в линеаризацию.
  • Наконец, оценивается статистика последовательности операторов.

Обратите внимание, однако, что параметры конструктора могутиспользоваться любыми конструкторами, которые следуют за ним.Поэтому его нужно инициализировать перед ними.Это делается в конце раздела 5.1.1:

Оценка вызова конструктора xc targs.,. (argsn) состоит из следующих шагов:

  • Сначала вычисляется префикс x .
  • Затем аргументы args1.,,, argsn оцениваются слева направо.
  • Наконец, создаваемый класс инициализируется путем оценки шаблона класса, на который ссылается c .

С этим у вас нет проблем, но у вас есть проблема с {stats} , выполняемым последним.Причина, по которой {stats} выполняется последним, заключается в том, что он может ссылаться на атрибуты своих классов и признаков предков, тогда как предки, очевидно, не знают о его потомках.Следовательно, предки должны быть полностью инициализированы до того, как {stats} будут выполнены.

Конечно, возможно, что do потребуется ранняя инициализация.Это описано в разделе 5.1.6. Ранние определения.Вот как бы вы написали это:

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