我想说我要创建一个List[(Int, Int)]
:
scala> (0 to 3).toList.zip(0 to 3)
res3: List[(Int, Int)] = List((0,0), (1,1), (2,2), (3,3))
但是,如果我想创建一个Stream[(Int, Int)]
,那该怎么办:
scala> (0 to 3).toList.zip(0 to 3).toStream
res4: scala.collection.immutable.Stream[(Int, Int)] = Stream((0,0), ?)
用于构建res4
的中间列表是否有资格进行垃圾回收?
答案 0 :(得分:1)
如果将列表视为包含列表' s head + link to the tail的对象,则答案是肯定的。
根据消息来源,在创建的流中没有输入列表的闭包,因此可以收集此列表(实际上只是" ::"案例类)。但是列表的尾部(" ::"' s的剩余链)被捕获在闭包内(var tlGen),直到你在流上迭代。
override def toStream : Stream[A] =
if (isEmpty) Stream.Empty
else new Stream.Cons(head, tail.toStream)
final class Cons[+A](hd: A, tl: => Stream[A]) extends Stream[A] {
override def isEmpty = false
override def head = hd
@volatile private[this] var tlVal: Stream[A] = _
@volatile private[this] var tlGen = tl _
def tailDefined: Boolean = tlGen eq null
override def tail: Stream[A] = {
if (!tailDefined)
synchronized {
if (!tailDefined) {
tlVal = tlGen()
tlGen = null
}
}
tlVal
}
}
https://github.com/scala/scala/blob/2.11.x/src/library/scala/collection/immutable/List.scala https://github.com/scala/scala/blob/2.11.x/src/library/scala/collection/immutable/Stream.scala#L1223
因此,当流完全迭代时,所有尾部都有资格进行收集。
例如,让我们选择List(1,2,3,4).toStream.foreach(_ => {}):
stream iteration captured tail generated stream eligible for GC
0 List(2, 3, 4) Stream(1, ?) List(1, 2, 3, 4)
1 List(3, 4) Stream(1, 2, ?) List(2, 3, 4)
2 List(4) Stream(1, 2, 3, ?) List(3, 4)
3 Nil Stream(1, 2, 3, 4) List(4)