I'm confused by how Rust for
loops work. Consider the following:
#![feature(core_intrinsics)]
fn print_type_of<T>(_: T) {
println!("{}", unsafe { std::intrinsics::type_name::<T>() });
}
fn main() {
let nums = vec![1, 2, 3];
for num in &nums { print_type_of(num); }
for num in nums { print_type_of(num); }
}
It outputs the following:
&i32
&i32
&i32
i32
i32
i32
What does it mean to pass in a vector into for
versus a reference to a vector? Why, when you pass in a reference, do you get a reference to the items and when you pass in an actual vector, you get the actual items?
The argument to a
for
loop must implementIntoIterator
. If you check out the docs forVec
, you will see these two implementations ofIntoIterator
:You get references for
&vec
and values forvec
because that's how the iterators are defined.Sometimes, you'll see these as the more explicit forms:
iter
orinto_iter
. The same logic applies; see What is the difference between iter and into_iter?There's another form that you will encounter:
&mut vec
anditer_mut
. These return mutable references to the elements in the vector.As to why the differences at all...
Using a reference to the vector allows you to access the vector after the loop is done. This compiles:
This does not:
Ownership-wise, you can't get a value from a reference unless you clone the value (assuming the type can even be cloned!). This means
&vec
is unable to yield values that aren't references.The implementer of
Vec
's iterator could have chosen to only yield references, but transferring ownership of the elements to the iterator allows the iterator's consumer to do more things; from a capability perspective it's preferred.See also: