没有"的Scala函数调用。" (点)vs使用"。" (点)

时间:2017-02-07 17:02:05

标签: scala stack-overflow primes operator-precedence lazy-sequences

有人可以帮我理解这里发生了什么。我有这个定义来生成素数:

def primes: Stream[Long] = {
    2 #:: 3 #:: 5 #:: 7 #::Stream.iterate(11L)(_ + 2).filter {
        n => primes takeWhile (p => p*p <= n) forall (n % _ != 0)
    }
}
def primes: Stream[Long] = {
    2 #:: 3 #:: 5 #:: 7 #::Stream.iterate(11L)(_ + 2) filter {
        n => primes takeWhile (p => p*p <= n) forall (n % _ != 0)
    }
}

正如您所看到的,两个定义完全相似,只是第二个定义在过滤器之前没有.,而第一个定义则没有。{/ p>

问题在于运行第一个,按预期运行并为我们提供素数,但第二个产生java.lang.StackOverflowError。 有人可以对此有所了解吗?在任何一种情况下传递给过滤器的是什么?

  

Scala版本:2.11.6

     

Java版本:1.8.0_121

这是我用来测试每​​个程序的完整程序:

object Main {

    def primes: Stream[Long] = {
        2 #:: 3 #:: 5 #:: 7 #::Stream.iterate(11L)(_ + 2) filter {
            n => primes takeWhile (_ <= sqrt(n)) forall (n % _ != 0)
        }
    }

    def primes2: Stream[Long] = {
        2 #:: 3 #:: 5 #:: 7 #::Stream.iterate(11L)(_ + 2).filter {
            n => primes2 takeWhile (p => p*p <= n) forall (n % _ != 0)
        }
    }

    def main(args: Array[String]): Unit = {
        println(primes.take(args.head.toInt).force)
    }
}

2 个答案:

答案 0 :(得分:8)

没有.的表示法具有与任何自定义中缀相同的优先级。因此,第一个仅将filter应用于Stream.iterate(11L)(_ + 2) - 第二个将其应用于2 #:: 3 #:: 5 #:: 7 #::Stream.iterate(11L)(_ + 2)

第一个工作的原因是当过滤器运行时元素2,3,5和7已经在primes中,所以当过滤器尝试使用primes时,这些元素是已经在里面了。

在第二个代码中并非如此,因为过滤器也应用于这些元素,这意味着它们不会出现在primes中,直到过滤器为它们返回true。但是过滤器需要在返回任何内容之前从prime中获取元素,因此在尝试获取元素时它会在无限递归中丢失。

答案 1 :(得分:2)

你需要括号:

&#xA;&#xA;
  def primes:Stream [Long] = {&#xA; 2#:: 3#:: 5#:: 7#::(Stream.iterate(11L)(_ + 2)过滤器{&#xA; n =&gt; primes takeWhile(p =&gt; p * p&lt; = n)forall(n%_!= 0)&#xA;})&#xA;}&#xA;  
&#xA;&#xA;

作为规则拇指,我通常到处都用点。它更容易阅读,并使这些错误难以出现。

&#xA;