Scala流计算抛出StackOverflowError

时间:2016-03-30 22:37:04

标签: scala stream stack-overflow

为什么此代码段执行会导致Series

StackOverflowError

虽然此代码段工作正常(请参阅lazy val primes: Stream[Int] = 2 #:: Stream.from(3, 2) filter { pc => primes.takeWhile(x => x * x <= pc) forall (p => pc % p != 0) } primes.take(5).last 之前的点):

filter

1 个答案:

答案 0 :(得分:6)

括号将使执行顺序更加明显。 // fails with stack overflow lazy val primes: Stream[Int] = (2 #:: Stream.from(3, 2)) filter { pc => primes.takeWhile(x => x * x <= pc) forall (p => pc % p != 0) } // succeeds lazy val primes: Stream[Int] = 2 #:: (Stream.from(3, 2).filter { pc => primes.takeWhile(x => x * x <= pc) forall (p => pc % p != 0) }) 的以下两个定义等同于OP中的各自定义。

(2 #:: Stream.from(3, 2))

好的,那么第一个错误是什么?首先通过创建流primes.head ,然后对其进行过滤来定义它。让我们尝试访问第一个元素:

head

这实际上也会产生堆栈溢出。这里发生了什么:

  1. primes尝试访问2的第一个元素。
  2. 必须根据filter谓词检查第一个元素primes
  3. 要检查谓词,我们必须递归访问primes
  4. 我们尝试使用filter的第一个元素,该元素必须在2上运行Stream谓词。
  5. 重复步骤3.
  6. ......这会导致堆栈溢出。

    第二个示例没有遇到此问题,因为22)的头部未被过滤,因此在该步骤没有递归检查是否{{ 1}}真的存在与否。换句话说,在第二个示例中,很明显2head的{​​{1}}。在第一个示例中,Stream的{​​{1}}必须通过检查head来计算,但为了这样做,在无限递归循环中引用它自己。