通常,如果你创建一个Stream
对象,头部会被急切地评估:
scala> Stream( {println("evaluating 1"); 1} , 2, 3)
evaluating 1
res63: scala.collection.immutable.Stream[Int] = Stream(1, ?)
如果我们创建一个在同一语句中作为前缀的 Stream,那么在连接之前没有评估头部似乎有点令人惊讶。
scala> 0 #:: Stream( {println("evaluating 1"); 1} , 2, 3)
res65: scala.collection.immutable.Stream[Int] = Stream(0, ?)
(#::
是右关联,是ConsWrapper
上的前置方法,是Stream
的隐式类。
这如何在前缀 0 之前不计算其头部?在我们从生成的流中获取值之前,尾流(或 cons 单元格(是否不存在堆上?但如果是这样,我们如何在尚不存在的对象上调用 #::
方法?
-Xprint:typer
是你的朋友,任何时候你都想确切地了解一些代码是如何计算的或推断类型的。
scala -Xprint:typer -e '0 #:: Stream( {println("evaluating 1"); 1} , 2, 3)'
val x$1: Int = 0;
Stream.consWrapper[Int](Stream.apply[Int]({
println("evaluating 1");
1
}, 2, 3)).#::(x$1)
consWrapper
的参数是按名称。所以即使这样也有效:
scala> (1 #:: (sys.error("!!"): Stream[Int])).head
res1: Int = 1
创建流的那一刻评估头部。
但是在第二个示例中,您不会传递 Streem 作为第二个参数来传递 by name 参数#::
,即根本不计算完整的表达式Stream( {println("evaluating 1"); 1} , 2, 3)
。