(rust noob here; I'm trying to understand what can/cannot/should/shouldn't be passed by reference in a higher order function situation)
let a = [1, 2, 3];
This invocation works:
let sum = a.iter().fold(0, |acc: i32, x: &i32| acc + x);
These do not:
let sum = a.iter().fold(0, |acc: i32, x: i32| acc + x);
let sum = a.iter().fold(0, |acc: &i32, x: i32| acc + x);
The error message is
error[E0631]: type mismatch in closure arguments
--> main.rs:8:22
|
8 | let sum = a.iter().fold(0, |acc: &i32, x: i32| acc + x);
| ^^^^ --------------------------- found signature of `for<'r> fn(&'r i32, i32) -> _`
| |
| expected signature of `fn({integer}, &{integer}) -> _`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0631`.
The explanation does not offer anything of interest. It says the arguments of the closure do not match those of the arguments of fold
. I however cannot see how it follows from the declaration of fold
:
fn fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B
Why is the second argument supposed to be &{integer}
, and the first one {integer}
?
The items in the iterator are borrowed from the array, so are &i32
not i32
. This form works because the accumulator is owned, while the items are borrowed:
let sum = a.iter().fold(0, |acc: i32, x: &i32| acc + x);
You can convert the iterator so its items are copied instead of referenced, and then the first form will work:
let sum = a.iter().copied().fold(0, |acc: i32, x: i32| acc + x);
The third form can never work. The closure needs to be able to return a new value with which to update the accumulator. The type of the accumulator is i32
. It can't be a reference because you can't return a reference from a closure (the original value would be dropped and Rust won't let you return a dangling pointer).