【发布时间】:2011-10-28 00:34:41
【问题描述】:
以下代码打印“*1”。令人困惑的是,如果我删除它返回“*4”的评论,这是我所期待的
var max = 0
lazy val list: Stream[Int] = 1 #:: Stream.from(2)
list.takeWhile {
x =>
max = x
x < 4
}//.foreach(println)
println("*" + max)
【问题讨论】:
标签: scala
以下代码打印“*1”。令人困惑的是,如果我删除它返回“*4”的评论,这是我所期待的
var max = 0
lazy val list: Stream[Int] = 1 #:: Stream.from(2)
list.takeWhile {
x =>
max = x
x < 4
}//.foreach(println)
println("*" + max)
【问题讨论】:
标签: scala
首先:第二行中的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 这样的东西使必要的。
您可以通过在 takeWhile 谓词中添加类似 println 的内容来更加显着地看到这一点:
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 来强制评估流的其余部分。
【讨论】: