流作为构造函数参数,有时在早期类初始化时完全求值



流可以用作类的构造函数参数:

scala> ( 0 to 10).toStream.map(i =>{println("bla" + i); -i})
bla0
res0: scala.collection.immutable.Stream[Int] = Stream(0, ?)
scala> class B(val a:Seq[Int]){println(a.tail.head)}
defined class B
scala> new B(res0)
bla1
-1
res1: B = B@fdb84e

所以,流没有得到完全的求值,尽管作为Seq参数提交,尽管部分求值。

我有一个这样的类:

class HazelSimpleResultSet[T] (col: Seq[T], comparator:Comparator[T]) extends HGRandomAccessResult[T] with CountMe
{
  val foo: Int = -1  // col of type Stream[T] already fully evaluated here.
  def count = col.size
  ....
}

其中HGRandomAccessResult和CountMe是简单接口。

在大多数情况下,我想使用流作为构造函数的参数,以避免昂贵的操作。在调试器中,我可以遵循它在某些情况下的工作,因为为col显示的值仍然是Stream(xy, ?)和"tlVal = null",即使在初始化HazelSimpleResultSet之后。

此外,为了进行测试,我在构造流的块中包括println,如下所示:

    keyvalues.foldLeft(Stream.empty[KeyType]){ case (a, b) => ({ println("evaluating "+ b); unpack[KeyType](b)}) #:: a}

,以便在控制台中准确地计算流的值。

所以,在某些情况下它是有效的,但在某些情况下,流在HazelSimpleResultSet初始化的第一个时刻得到完整的评估。我看不出在提交的流中有什么相关的差异,我只是确定它们在那一刻之前都是未评估的流。用调试器"进入",我可以看到它在类定义本身的行中被评估,甚至在到达类体之前,即在任何字段初始化之前。

编辑:我可以以一种(次优)方式定义类,这样根本没有字段引用流,并且仍然可以得到该行为。

CountMe接口定义了一个"count"方法,该方法调用col.size,然后计算所有流。我尝试用lazy val的大小来定义count,但是没有什么区别。

我有点不明白为什么它在某些情况下不起作用。有人对流的隐藏警告有什么提示吗?

编辑:重要提示:Stream对象包装了一些需要评估的严肃状态,例如对NoSQL数据库(hazelcast)的引用。问题:这里有什么需要注意的?当我的流携带评估所需的有状态引用时,是否有一些特别的事情我必须注意?

如果您像这样创建Stream:

Stream ({println("eval 1"); 1}, {println("eval 2"); 2})

那么你实际上是在调用Stream.apply它是这样实现的:

/** A stream consisting of given elements */
override def apply[A](xs: A*): Stream[A] = xs.toStream

意味着实际发生的是:

  1. 所有元素都被求值!
  2. 创建包含这些元素的Seq
  3. Seq创建Stream

因此,正如您所看到的,如果您以这种方式创建Stream,则它的所有元素都被急切地求值。这不是创建惰性求值Stream的方法。您想要做的可能是使用#::#:::运算符来惰性地计算其操作数。

相关内容

  • 没有找到相关文章

最新更新