2012-03-25 68 views
10

一般来说,如果你创建一个Stream对象时,头部会急切地评价:什么时候流的头部被评估?

scala> Stream({println("evaluating 1"); 1} , 2, 3) 
evaluating 1 
res63: scala.collection.immutable.Stream[Int] = Stream(1, ?) 

如果我们创造,我们在同一个语句前面加上流,似乎稍稍令人意外的是,头未评估前串联。即

scala> 0 #:: Stream({println("evaluating 1"); 1} , 2, 3) 
res65: scala.collection.immutable.Stream[Int] = Stream(0, ?) 

#::是右结合并且是ConsWrapper的前置方法,该方法是隐式类Stream。)

这是如何不前面加上0之前评估其头?是否直到我们从结果流中取值,尾流(或​​cons单元)才存在于堆上?但是如果是这样的话,我们如何在尚不存在的对象上调用#::方法?

+1

我建议你使用'javap'来理解发生了什么。 – 2012-03-25 02:14:48

+0

我想出来看看源代码(假设我的回答是正确的) – 2012-03-25 06:52:59

回答

7

-Xprint:typer-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 
+0

使用'-e'的+1。我认为与Perl的相比,它的用处不大。 – 2012-03-25 21:51:33

+0

我现在明白了。同样重要的是,Stream to ConsWrapper中的隐式def是以名称命名的。 'implicit def conswrapper [A](stream:=> Stream [A])''。这大概是为什么'ConsWrapper'存在,并且'#::'不是'Stream'直接的方法:所以不必创建Stream来调用这个方法 - 你只需要一个'ConsWrapper'对象包含功能的子集。 – 2012-03-29 01:25:17

5

头在流创建时被评估。

但是在第二个示例中,您不通过Streem作为#::的第二个参数,您传递了一个名称参数,即完全不会评估完整表达式Stream({println("evaluating 1"); 1} , 2, 3)

相关问题