ふつうの関数型言語の感覚でfold
すると、参照で詰む。
例題として、任意個の整数の最大公約数の計算を考える。
誤ったコード
fn gcd(a: u32, b: u32) -> u32 {
assert!(a != 0 || b != 0);
if a == 0 { b }
else { gcd(b % a, a) }
}
fn main() {
let nums = [799459, 28823, 27347];
if let Some((head, tail)) = nums.split_first() {
println!("gcd = {}", tail.iter().fold(head, gcd));
}
}
正しいコード
fn gcd(a: u32, b: u32) -> u32 {
assert!(a != 0 || b != 0);
if a == 0 { b }
else { gcd(b % a, a) }
}
fn main() {
let nums = [799459, 28823, 27347];
// &head に注意
if let Some((&head, tail)) = nums.split_first() {
// &b に注意
println!("gcd = {}", tail.iter().fold(head, |a,&b| gcd(a,b)));
}
}
-
slice::split_first
は参照を返すので、&head
で受けて参照を剥がさなければならない -
fold
する関数の第二引数には参照が渡ってくるので、&b
で受けて参照を剥がさなければならない
fold
に渡す関数の引数と戻り値が参照である場合は、この罠には嵌まらない。