其他海报已经给出了很好的答案,我不会重复他们已经说过的话。正如您在问题中给出了一个 Scala 示例,我将给出一个 Scala 特定示例。正如Tricks 已经说过的那样,foldRight 需要保留n-1 堆栈帧,其中n 是您的列表的长度,这很容易导致堆栈溢出——甚至尾递归也无法将您从这个问题中解救出来.
List(1,2,3).foldRight(0)(_ + _) 将简化为:
1 + List(2,3).foldRight(0)(_ + _) // first stack frame
2 + List(3).foldRight(0)(_ + _) // second stack frame
3 + 0 // third stack frame
// (I don't remember if the JVM allocates space
// on the stack for the third frame as well)
而List(1,2,3).foldLeft(0)(_ + _) 将简化为:
(((0 + 1) + 2) + 3)
可以迭代计算,如implementation of List 中所做的那样。
在严格评估的 Scala 语言中,foldRight 可以轻松地将堆栈用于大型列表,而 foldLeft 不会。
例子:
scala> List.range(1, 10000).foldLeft(0)(_ + _)
res1: Int = 49995000
scala> List.range(1, 10000).foldRight(0)(_ + _)
java.lang.StackOverflowError
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRig...
因此,我的经验法则是 - 对于没有特定关联性的运算符,请始终使用 foldLeft,至少在 Scala 中是这样。否则,请参考答案中给出的其他建议;)。