次の状況で
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(1)ではなくO(N)を消費します。
次の状況で
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(1)ではなくO(N)を消費します。
特性に対して末尾再帰メソッドが生成されます。トレイトのエクステンダー(ここO
)のメソッドエントリは、呼び出しをトレイトのメソッドに転送しますが、そうしている間、ストリームのヘッドへの参照を保持します。
したがって、このメソッドは末尾再帰ですが、メモリを解放することはできません。対処法:ストリーム関数を特性で定義しないでください。オブジェクトで直接定義してください。
別の方法はscalazですEphemeralStream
。これは、ストリームのヘッドとテールへの弱参照を保持し、必要に応じてそれらを再計算します。