4

我想为 BigDecimal 列表编写一个简短的函数求和函数,并尝试使用:

def sum(xs: List[BigDecimal]): BigDecimal = (0 /: xs) (_ + _)

但我收到了这个错误信息:

<console>:7: error: overloaded method value + with alternatives:
  (x: Int)Int <and>
  (x: Char)Int <and>
  (x: Short)Int <and>
  (x: Byte)Int
 cannot be applied to (BigDecimal)
       def sum(xs: List[BigDecimal]): BigDecimal = (0 /: xs) (_ + _)
                                                                ^

如果我改用 Int,则该函数有效。我猜这是因为 BigDecimal 的运算符重载了+. BigDecimal 有什么好的解决方法?

4

4 回答 4

17

问题在于初始值。解决方案在这里,非常简单:

 sum(xs: List[BigDecimal]): BigDecimal = (BigDecimal(0) /: xs) (_ + _)
于 2011-09-23T22:47:16.177 回答
2

foldLeft 需要一个初始化值。

def foldLeft[B](z: B)(f: (B, A) ⇒ B): B

此初始化值(名为z)必须与要折叠的类型具有相同的类型:

(BigDecimal(0) /: xs) { (sum: BigDecimal, x: BigDecimal) => sum+x }
// with syntax sugar
(BigDecimal(0) /: xs) { _+_ }

如果您添加一个 Int 作为初始化值,则 foldLeft 将如下所示:

(0 /: xs) { (sum: Int, x: BigDecimal) => sum+x } // error: not possible to add a BigDecimal to Int
于 2011-09-23T22:55:35.917 回答
2

在这种情况下(累加器与列表中的项目具有相同的类型),您可以通过添加列表中的第一项和第二项来开始折叠——即,您不一定需要起始值。Scalareduce提供了这种折叠:

def sum(xs: List[BigDecimal]) = xs.reduce(_ + _)

如果您的操作不是关联的,也有reduceLeft和版本。reduceRight

于 2011-09-23T23:36:12.980 回答
0

正如其他人已经说过的那样,由于初始值而出现错误,因此正确的方法是将其包装在 BigDecimal 中。另外,如果你有很多这样的函数并且不想BigDecimal(value)到处写,你可以像这样创建隐式转换函数:

implicit def intToBigDecimal(value: Int) = BigDecimal(value)

下次 Scala 会默默地将所有 Ints(包括常量)转换为 BigDecimal。事实上,大多数编程语言都使用从整数到小数甚至从小数到分数的静默转换(例如 Lisps),因此这似乎是非常合乎逻辑的举动。

于 2011-09-23T23:05:43.067 回答