问题描述
以下情况
trait T {
@tailrec
def consume[A](as: Stream[A]): Unit = {
if (as.isEmpty) ()
else consume(as.tail)
}
}
object O extends T
调用O.consume(Range(1, N).toStream)
,N
足够大,程序会耗尽内存,或者至少会消耗O(N) 而不是所需的 O(1).
calling O.consume(Range(1, N).toStream)
with N
big enough, the program will run out of memory, or at least will consume O(N) instead of the needed O(1).
推荐答案
为 trait 生成尾递归方法.trait 扩展器中的方法入口(这里是 O
)将调用转发到 trait 的方法,但在这样做的同时,它保留了对流头部的引用.
The tail-recursive method is generated for the trait. The method entry in the extender of the trait (here O
) forwards the call to the method of the trait, but while doing so, it keeps a reference to the head of the Stream.
因此该方法是尾递归的,但仍然无法释放内存.补救措施:不要在 trait 中定义 Stream 函数,直接在对象中定义即可.
Thus the method is tail-recursive, but memory still can't be released. Remedy: Don't define Stream functions in traits, just directly in objects.
另一种方法是 scalaz 的 EphemeralStream
,它持有对流头和尾的弱引用,并根据需要重新计算它们.
An alternative is scalaz's EphemeralStream
, which holds weak references to the stream head and tail, and recomputes them on demand.
这篇关于在 trait 中定义的 Scala 尾递归流处理器函数保存对流头的引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!