Let's create a vec of integers, iterate through and print the individual values, and then afterward, print out the whole vec. Here is the code:
fn main() {
let some_ints = vec![1,2,3,4,5];
for i in some_ints {
dbg!(i);
}
dbg!(some_ints);
}
Simple right? Well nope. Trying to compile the above code will fail with the following errors:
error[E0382]: use of moved value: `some_ints`
--> src/main.rs:9:9
|
4 | let some_ints = vec![1,2,3,4,5];
| --------- move occurs because `some_ints` has type `Vec<i32>`,
which does not implement the `Copy` trait
5 | for i in some_ints {
| --------- `some_ints` moved due to this implicit call to `.into_iter()`
...
9 | dbg!(some_ints);
| ^^^^^^^^^ value used here after move
|
note: this function takes ownership of the receiver `self`, which moves `some_ints`
help: consider iterating over a slice of the `Vec<i32>`'s
content to avoid moving into the `for` loop
|
5 | for i in &some_ints {
| +
For more information about this error, try `rustc --explain E0382`
Why is this the case? Why is the borrow checker preventing the use of a vec after a simple iteration?
Well, the answer to that question lies in Rust's implementation of the Iterator pattern - which by the way, is what makes it possible to use the for…in
syntax.
Iterators are not special or unique to Rust. The concept can be found in a handful of languages. I wrote about the Iterator pattern as it exists in JavaScript in the post Iterables and Iterators in JavaScript.
The unique thing about the Iterator pattern in Rust is its interaction with the borrow checker.
If this interaction with the borrow checker is not taken into consideration then it is possible to bump into certain confusing compile errors while attempting to use the iterator pattern.
So to get started answering the question of why the borrow checker prevents what looks like a legit code above, let's take a look at the Iterator pattern and what is special about it in Rust.