我想为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有什么好的解决方法?
答案 0 :(得分:16)
问题在于初始值。解决方案就在这里,非常简单:
sum(xs: List[BigDecimal]): BigDecimal = (BigDecimal(0) /: xs) (_ + _)
答案 1 :(得分: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
答案 2 :(得分:2)
在这种情况下(累加器与列表中的项目具有相同的类型),您可以通过添加列表中的第一个和第二个项目来开始折叠 - 即,您不一定需要起始值。 Scala的reduce
提供了这种折叠:
def sum(xs: List[BigDecimal]) = xs.reduce(_ + _)
如果您的操作不是关联的,还有reduceLeft
和reduceRight
个版本。
答案 3 :(得分:0)
正如其他人已经说过的那样,由于初始值而出现错误,因此正确的方法是将其包装在BigDecimal中。另外,如果你有许多这样的函数而且不想在任何地方写BigDecimal(value)
,你可以创建这样的隐式转换函数:
implicit def intToBigDecimal(value: Int) = BigDecimal(value)
下次Scala会默默地将所有Int(包括常量)转换为BigDecimal。事实上,大多数编程语言使用从整数到十进制甚至从小数到分数(例如Lisps)的静默转换,因此它似乎是非常合理的移动。