Przede wszystkim: lazy
w drugiej linii nie robi nic, można go usunąć i uzyskać ten sam wynik.
Co ważniejsze: takeWhile
jest faktycznie leniwy, że to po prostu zwraca kolejny Stream
i nic przeszłość szefa tego strumienia będą oceniane, dopóki nie jest potrzebne. Rozważmy następujący:
val s = Stream.from(1).takeWhile(_ > 0)
Ty i ja wiemy, że s
będzie nieskończony strumień, ale jeśli chcemy odpalić rEPL i wpisać to w, to doskonale chętnie go ocenić:
scala> val s = Stream.from(1).takeWhile(_ > 0)
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
To samo dzieje się w twoim przykładzie: (Int) ⇒ Boolean
, który przeszedłeś na takeWhile
, nie będzie zasilany żadnymi elementami poza strumieniem strumienia, dopóki coś takiego jak twój foreach
nie uczyni tego koniecznym.
Widać to nawet bardziej dramatycznie dodając coś jak println
wewnątrz z takeWhile
orzecznika:
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)
Wyraźnie orzecznik tylko jest wywoływana za głowę strumienia, aż zmusimy oceny resztę strumienia dzwoniąc pod numer toList
.