Обоснование поведения, преобладающего над val - PullRequest
6 голосов
/ 07 октября 2011
class A { 
  val x = println("A") 
}
class B extends A {
  override val x = println("B")
}
(new B).x

Отпечатки:

A
B

Однако,

class A { 
  lazy val x = println("A") 
}
class B extends A {
  override lazy val x = println("B")
}
(new B).x

Отпечатки просто:

B

По Мартину Одерскому поведение, по крайней мере, в не ленивом случае, "как указано".Мне любопытно, почему поведение определяется таким образом, и почему оно отличается, когда val ленив.

Ответы [ 2 ]

12 голосов
/ 07 октября 2011

Код в шаблоне ("теле") определения класса, вне определений членов, - это то, что входит в конструктор.Конструкторы для родительских классов всегда вызываются, когда вы инициализируете экземпляр дочернего класса (в этом случае вы вызываете конструктор без аргументов, в противном случае синтаксис будет class B extends A(arg1, arg2) { ... }).Для получения более подробной информации см. Раздел 5.1 в Спецификации языка Scala .

Именно поэтому println("A") оценивается в первом случае;это определение val является частью кода конструктора.

Когда вы думаете о том, что происходит во время построения во втором примере, вы никогда не спрашивали значение x, определенное в A;теперь, поскольку это lazy val, он не будет вычислен до того, как это потребуется.

Вы можете думать о lazy val s как о методах, которые не принимают аргументов и кэшируют свои выходные данные при первом вызове.,Вы не вызывали этот метод здесь, вы просто определили его.

1 голос
/ 07 октября 2011
class A { 
  val x = println("A") 
}
class B extends A {
  override val x = println("B")
}
(new B).x

Во время выполнения конструктора выполняются все инициализации val s (и других операторов). Следовательно, val x = println("A") запускается как часть конструкции A, а override val x = println("B") запускается как часть конструкции B. Они оба печатают некоторую строку и инициализируют x в () (типа Unit), поэтому переопределение - это просто красная сельдь. .x (из (new B).x) ничего не делает.

В ленивом случае вы инициализируете x чем-то вроде функции без аргументов и возвращаете Unit. Он не запускается, пока вы не прочитаете .x, и, поскольку x переопределен, в этом случае печатается только буква "B".

...