2011-10-28 11 views
10

Poniższy kod wypisuje "* 1". Co się tajemnicze jest jeśli usunąć komentarz powraca „* 4”, który jest, czego się spodziewałemDlaczego moja praca nie działa z moim strumieniem

var max = 0 
lazy val list: Stream[Int] = 1 #:: Stream.from(2) 
list.takeWhile { 
    x => 
    max = x 
    x < 4 
}//.foreach(println) 
println("*" + max) 

Odpowiedz

20

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.

Powiązane problemy