Ответ 1
Прежде всего: lazy
во второй строке ничего не делает - вы можете удалить его и получить тот же результат.
Что еще более важно: takeWhile
на самом деле ленив, потому что он просто возвращает другой Stream
, и ничто мимо заголовка этого потока не будет оценено до его появления. Рассмотрим следующее:
val s = Stream.from(1).takeWhile(_ > 0)
Вы и я знаем, что s
будет бесконечным потоком, но если мы запустим REPL и наберем это, он с удовольствием оценит его:
scala> val s = Stream.from(1).takeWhile(_ > 0)
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
То же самое происходит в вашем примере: (Int) ⇒ Boolean
, который вы передали в takeWhile
, не будет получать какие-либо элементы за пределами заголовка потока, пока что-то вроде вашего foreach
не сделает это необходимо.
Вы можете увидеть это еще более резко, добавив что-то вроде println
внутри предиката takeWhile
:
scala> val s = Stream.from(1).takeWhile { x => println("Checking: " + x); x < 4 }
Checking: 1
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> val l = s.toList
Checking: 2
Checking: 3
Checking: 4
l: List[Int] = List(1, 2, 3)
Ясно, что предикат только вызывается для заголовка потока, пока мы не заставим оценку остальной части потока, вызвав toList
.