This aspect of Rust seems rather bizarre at first, and I'd like to know how for
typing works in this case.
fn sum1(v: &mut Vec<i32>) -> i32 {
// I know I don't mutate v, but that's not the point
let mut s = 0;
for e in v {
s += *e;
// s += e; <- Err!
}
s
}
fn sum2(v: &Vec<i32>) -> i32 {
let mut s = 0;
for e in v {
s += e; // Okay?
}
s
}
fn main() {
let mut v = vec![1, 2, 3];
println!("{}", sum1(&mut v));
println!("{}", sum2(&v));
}
At first I was confused as to why it wanted me to dereference in sum1
. But okay, it's saying AddAssign<&mut i32>
is not implemented, so I see that e
is &mut i32
. That's really awesome for changing e
on the fly.
But now, with that information, why does sum2
compile? It seems like AddAssign<&i32>
is indeed implemented (Which I tested separately), so it's possible that it's using that AddAssign
method on a &i32
, but then again it's also possible that e
is simply i32
. My question boils down to:
Is e
an i32
, or an &i32
?
I don't know enough about references to easily check the difference myself (By using something other than i32
and checking for crashes). &i32
is the most logical but I would like to know for sure.
Coming from C, mixing between pointers and values is extremely confusing, and it has already taken me quite a bit to get used to with functions automatically dereferencing/referencing their arguments (which I don't think I've really done yet).
EDIT:
The type could be verified (And answer my question) with How do I print the type of a variable in Rust?, which is useful to mess around with but doesn't directly answer how for loops work. What is the exact definition of the for loop in Rust? helps a lot, and What is the difference between iter and into_iter? talks about a related IntoIterator
trait that can cause for loop confusion.