Статья в Википедии для Scala даже отвечает на то, что делает ключевое слово lazy
:
Использование ключевого слова lazy откладывает инициализацию значения до тех пор, пока это значение не будет использовано.
Кроме того, в этом примере кода с q : => Parser[U]
имеется параметр call-by-name.Параметр, объявленный таким образом, остается неоцененным, пока вы явно не оцените его где-нибудь в своем методе.
Вот пример из REPL scala о том, как работают параметры вызова по имени:
scala> def f(p: => Int, eval : Boolean) = if (eval) println(p)
f: (p: => Int, eval: Boolean)Unit
scala> f(3, true)
3
scala> f(3/0, false)
scala> f(3/0, true)
java.lang.ArithmeticException: / by zero
at $anonfun$1.apply$mcI$sp(<console>:9)
...
Как видите, 3/0
вообще не оценивается во втором вызове.Объединение ленивого значения с параметром call-by-name, как указано выше, приводит к следующему значению: параметр q
не оценивается сразу при вызове метода.Вместо этого ему присваивается значение lazy p
, которое также не оценивается сразу.Только позже, когда используется p
, это приводит к оценке q
.Но, поскольку p
является val
, параметр q
будет оцениваться только один раз , а результат сохраняется в p
для последующего повторного использования в цикле.
YouВ репле легко увидеть, что множественная оценка может произойти иначе:
scala> def g(p: => Int) = println(p + p)
g: (p: => Int)Unit
scala> def calc = { println("evaluating") ; 10 }
calc: Int
scala> g(calc)
evaluating
evaluating
20