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::reduce
や Iterator::fold
でも書ける。
ただし、sum
や product
を使ったほうが短くなりやすい。
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
トレイトにより実現されている。
以下では、&i32
を i32
に対して集約している。
fn main() {
let vals = vec![&1, &2, &3, &4, &5].into_iter();
let sum = vals.clone().sum::<i32>();
assert_eq!(sum, 15);
}
以下では、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)
}
}