Iterator::sum メソッドと Iterator::product メソッドについて。

基礎知識

Iterator::sum はイテレータの全要素の総和を求める。

Iterator::product はイテレータの全要素の総乗を求める。


fn main() {
    let vals = vec![1, 2, 3, 4, 5].into_iter();
    let sum = vals.clone().sum::<i32>();
    let prd = vals.clone().product::<i32>();
    assert_eq!(sum, 15);
    assert_eq!(prd, 120);
}

他メソッドでの代用

同じ処理は Iterator::reduceIterator::fold でも書ける。

ただし、sumproduct を使ったほうが短くなりやすい。


fn main() {
    let vals = vec![1, 2, 3, 4, 5].into_iter();
    let sum1 = vals.clone().sum::<i32>();
    let sum2 = vals.clone().reduce(|a, x| a + x).unwrap();
    let sum3 = vals.clone().fold(0, |a, x| a + x);
    assert_eq!(sum1, sum2);
    assert_eq!(sum1, sum3);
}

明示的な型パラメタ

よくある使い方の範囲では、型パラメタを明示している箇所について、「ここは型推論できるのでは?」と思える。しかし、これは「何を集約するか?」だけでなく「何を何に対して集約するか?」まで汎用性を持たせた対償となっている。

なお、この汎用性は Sum トレイトや Product トレイトにより実現されている。

サンプル 1

以下では、&i32i32 に対して集約している。


fn main() {
    let vals = vec![&1, &2, &3, &4, &5].into_iter();
    let sum = vals.clone().sum::<i32>();
    assert_eq!(sum, 15);
}

サンプル 2

以下では、Sum を実装して独自の総和を定義している。


use std::iter::Sum;

fn main() {
    let items = vec!["foo", "bar", "baz"].into_iter();
    let sum = items.sum::<MySummary>();
    assert_eq!(sum.0, "foo-bar-baz");
}

struct MySummary(String);

impl<'a> Sum<&'a str> for MySummary {
    fn sum<I: Iterator<Item = &'a str>>(iter: I) -> Self {
        let mut ret = String::new();
        for item in iter {
            ret += if ret.is_empty() { "" } else { "-" };
            ret += &item.to_string();
        }

        Self(ret)
    }
}