Scala:尽管在添加时使用了Long,但仍会溢出

Tre*_*ton 5 scala

在2.7.5.final,我试图添加一个Intrable Int这样的列表

def sum(xs: Iterable[Int]): Long = {
  var sum = 0L
  xs.foreach((x) => sum = sum + x)
  sum
}

println(sum(List(1, Integer.MAX_VALUE - 1)))
println(sum(Integer.MAX_VALUE - 1 to Integer.MAX_VALUE))
println(0L + Integer.MAX_VALUE - 1 + Integer.MAX_VALUE)
Run Code Online (Sandbox Code Playgroud)

当我跑步时,我明白了

2147483647
0
4294967293
Run Code Online (Sandbox Code Playgroud)

并且,您可能会说"使用reduceLeft(_ + _)",但它似乎只能返回与列表中的元素相同的类型...但我想积累到Long,所以我没有溢出问题.

更新2009-10-28

正如Eastsun所指出的,这是Range中的一个错误.已经向Scala团队报告了2535号机票

Eas*_*sun 7

这是Range的一个错误.有一个Range的foreach方法的源代码:

override def foreach(f: Int => Unit) {
if (step > 0) {
  var i = this.start
  *val until = if (inInterval(end)) end + 1 else end*      //bug here!!!

  while (i < until) {
    f(i)
    i += step
  }
} else {
  var i = this.start
  val until = if (inInterval(end)) end - 1 else end

  while (i > until) {
    f(i)
    i += step
  }
}
Run Code Online (Sandbox Code Playgroud)

}


Fla*_*gan 5

Eastsun的回答给出了计算溢出的一个很好的理由.作为一种解决方法,我将重新定义sum要使用的函数foldLeft,它允许您指定累加器.

def sum(xs: Iterable[Int]): Long =
  xs.foldLeft(0L)(_ + _)
Run Code Online (Sandbox Code Playgroud)

或使用速记foldLeft(我非常喜欢,因为它将折叠的起始值放在Iterable你试图折叠的前面).

def sum(xs: Iterable[Int]): Long =
  (0L /: xs)(_ + _)
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,您尝试运行的代码都会给出正确的结果.

- Flaviu Cipcigan