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 implement IntoIterator
. If you check out the docs for Vec
, you will see these two implementations of IntoIterator
:
impl<T> IntoIterator for Vec<T> {
type Item = T;
type IntoIter = IntoIter<T>
}
impl<'a, T> IntoIterator for &'a Vec<T> {
type Item = &'a T;
type IntoIter = Iter<'a, T>
}
You get references for &vec
and values for vec
because that's how the iterators are defined.
Sometimes, you'll see these as the more explicit forms: iter
or into_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
and iter_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:
let v = vec![1, 2, 3];
for i in &v {}
for i in &v {}
This does not:
let v = vec![1, 2, 3];
for i in v {}
for i in v {}
error[E0382]: use of moved value: `v`
--> src/main.rs:4:14
|
3 | for i in v {}
| - value moved here
4 | for i in v {}
| ^ value used here after move
|
= note: move occurs because `v` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With