问题描述
以下代码打印*1".令人困惑的是,如果我删除评论,它会返回*4",这正是我所期待的
The following code prints "*1". What's mystifying is if I remove the comment it returns "*4" which is what I was expecting
var max = 0
lazy val list: Stream[Int] = 1 #:: Stream.from(2)
list.takeWhile {
x =>
max = x
x < 4
}//.foreach(println)
println("*" + max)
推荐答案
首先:第二行中的 lazy
没有做任何事情——你可以删除它并获得相同的结果.
First of all: the lazy
in your second line isn't doing anything—you can remove it and get the same result.
更重要的是:takeWhile
实际上是懒惰的,因为它只返回另一个Stream
,并且没有超过那个流的头部评估直到需要.考虑以下几点:
More importantly: takeWhile
is actually lazy, in that it just returns another Stream
, and nothing past the head of that stream will be evaluated until it's needed. Consider the following:
val s = Stream.from(1).takeWhile(_ > 0)
你和我都知道 s
将是一个无限流,但如果我们启动 REPL 并输入它,很高兴评估它:
You and I know that s
is going to be an infinite stream, but if we fire up the REPL and type this in, it's perfectly happy to evaluate it:
scala> val s = Stream.from(1).takeWhile(_ > 0)
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
在您的示例中发生了同样的事情:您传递给 takeWhile
的 (Int) ⇒ Boolean
不会被提供给超出流的头部,直到您的 foreach
之类的东西使之成为必需.
The same thing is happening in your example: the (Int) ⇒ Boolean
that you've passed to takeWhile
isn't going to get fed any elements beyond the head of the stream, until something like your foreach
makes that necessary.
通过在 takeWhile
谓词中添加类似 println
之类的内容,您可以更显着地看到这一点:
You can see this even more dramatically by adding something like a println
inside of the takeWhile
predicate:
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
强制对流的其余部分进行评估.
Clearly the predicate only gets called for the head of the stream, until we force the evaluation of the rest of the stream by calling toList
.
这篇关于为什么我的 takeWhile 无法与我的 Stream 一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!