2011-10-28 22 views
10

以下代码打印“* 1”。什么是神秘的是,如果我删除的评论则返回“* 4”,这是我所期待的为什么我的takeWhile无法使用我的流

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

回答

20

首先:在你的第二个行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, ?) 

您的示例中发生了同样的事情:您传递给takeWhile(Int) ⇒ Boolean将不会获得流头之外的任何元素,直到像foreach这样的东西使得必需。

您可以通过添加像一个printlntakeWhile谓词的内部更为显着看到这一点:

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的其余部分流。