If I try to iterate over a slice twice, it works fine:
let a = &[1, 2, 3];
for i in a {
println!("{}", i);
}
for i in a { // works fine
println!("{}", i);
}
If I try to iterate over a vector twice, it fails:
let a = vec![1, 2, 3];
for i in a {
println!("{}", i);
}
for i in a {
println!("{}", i);
}
error[E0382]: use of moved value: `a`
--> src/main.rs:6:14
|
3 | for i in a {
| - value moved here
...
6 | for i in a {
| ^ value used here after move
|
= note: move occurs because `a` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
I see that the IntoIterator
trait takes self
by value, so it makes sense to me that the second example fails. Why does the first example succeed?
Iterators can generally not be iterated twice because there might be a cost to their iteration. In the case of str::lines , each iteration needs to find the next end of line, which means scanning through the string, which has some cost.
Traversal: Traversal in an array of vectors is perform using iterators. Above pseudo-code traverses vector <int> A[n] at each index using starting iterators A[i]. begin() and ending iterator A[i]. end().
Like you said, for
works by taking the thing you asked it to iterate over, and passing it through IntoIterator::into_iter
to produce the actual iterator value. Also as you said, into_iter
takes the subject by value.
So, when you try to iterate over a Vector
directly, this means you pass the entire vector, by value, into its IntoIterator
implementation, thus consuming the vector in the process. Which is why you can't iterate over a vector directly twice: iterating over it the first time consumes it, after which it no longer exists.
However, slices are different: a slice is an immutable, borrowed pointer to its data; immutable, borrowed pointers can be copied freely. This means that the IntoIterator
for immutable slices just borrows the data and doesn't consume it (not that it could). Or, to look at it another way, its IntoIterator
implementation is simply taking a copy of the slice, whereas you can't copy a Vec
.
It should be noted that you can iterate over a Vec
without consuming it by iterating over a borrow. If you check the documentation for Vec
, you'll note that it lists implementations of IntoIterator
for Vec<T>
, &Vec<T>
and &mut Vec<T>
.
let mut a: Vec<i32> = vec![1, 2, 3];
for i in &a { // iterate immutably
let i: &i32 = i; // elements are immutable pointers
println!("{}", i);
}
for i in &mut a { // iterate mutably
let i: &mut i32 = i;// elements are mutable pointers
*i *= 2;
}
for i in a { // iterate by-value
let i: i32 = i; // elements are values
println!("{}", i);
}
// `a` no longer exists; it was consumed by the previous loop.
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