4

BigDecimal の List に対して短い関数 sum-function を書きたいと思い、次のようにしてみました:

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

このような状況 (accumulator がリスト内の項目と同じ型を持つ) では、リスト内の最初と 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 はすべての Int (定数を含む) を黙って BigDecimal に変換します。実際、ほとんどのプログラミング言語は、整数から 10 進数、さらには 10 進数から分数 (Lips など) へのサイレント変換を使用しているため、非常に論理的な動きのようです。

于 2011-09-23T23:05:43.067 に答える