2

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

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 参数提交,并且虽然被部分评估,但 Stream 并未得到完全评估。按预期工作。

我有这样的课:

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 是简单的接口。

大多数情况下,我想使用 Streams 作为 col 构造函数参数,以避免昂贵的操作。在调试器中,我可以看出它在某些情况下有效,因为 col 显示的值仍然是 Stream(xy, ?) 和“tlVal = null”,即使在 HazelSimpleResultSet 初始化之后也是如此。

此外,为了测试,我在构建 Streams 的块中包含 println,如下所示:

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

以便在准确评估 Stream 时在控制台中跟踪。

因此,在某些情况下它可以工作,但在某些情况下,Stream 在 HazelSimpleResultSet 初始化的最初时刻得到全面评估。我看不出提交的 Stream 没有相关差异,我只是确定他们在那一刻之前是未经评估的 Streams。使用调试器“进入”,我可以看到它在类定义本身的行中被评估,甚至在到达类主体之前,即在任何字段的初始化之前。

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

CountMe 接口定义了一个“count”方法,该方法调用 col.size,然后评估所有 Stream。我试图根据惰性 val 大小来定义计数,但这并没有什么不同。

我有点不知所措,为什么它在某些情况下不起作用。有人对 Streams 的隐藏警告有任何提示吗?

编辑:重要说明:Stream 对象包含了一些需要评估的严重状态,即对 NoSQL 数据库(hazelcast)的引用。问题:这里有什么注意事项?当我的 Stream 携带评估所需的有状态引用时,有什么特别需要注意的吗?

4

1 回答 1

1

如果你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创建包含这些元素的A。
  3. AStream是由此创建的Seq

如您所见,如果您以Stream这种方式创建,它的所有元素都会被急切地评估。这不是您创建 lazily-evaluated 的方式Stream。您想要做的可能是使用#::#:::懒惰地评估其操作数的运算符。查找文档以了解它们的用法。

于 2013-03-11T13:42:04.980 回答