Прежде всего: 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
.