10

This doesn't work:

let vectors = vec![1, 2, 3, 4, 5, 6, 7];

for i in vectors {
    println!("Element is {}", i);
}

let largest = vectors[0];

Error message:

error[E0382]: borrow of moved value: `vectors`
 --> src/main.rs:8:19
  |
2 |     let vectors = vec![1, 2, 3, 4, 5, 6, 7];
  |         ------- move occurs because `vectors` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
3 | 
4 |     for i in vectors {
  |              -------
  |              |
  |              value moved here
  |              help: consider borrowing to avoid moving into the for loop: `&vectors`
...
8 |     let largest = vectors[0];
  |                   ^^^^^^^ value borrowed here after move

The vector has been moved into the loop. Its ownership — and that of its individual elements — has been transferred there permanently.

But this works:

let largest = vectors[0];
let largest2 = vectors[0];

I don't know why; the vectors[0] value should have been moved to largest and largest2 should then fail, but it didn't.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
GraphicalDot
  • 2,644
  • 2
  • 28
  • 43

2 Answers2

10

When you use vectors inside a for..in loop, Rust will call the IntoIterator::into_iter trait method of the Vec, which takes ownership of self. Therefore you cannot use vectors afterwards.

use std::iter::IntoIterator;

// these are equivalent
for i in vectors { /* ... */ }
for i in IntoIterator::into_iter(vectors) { /* ... */ }

The index operator, on the other hands, calls the Index::index trait method of the Vec, which takes self by reference. Additionally, it automatically dereferences the value, so that if the items inside the vector implement Copy, they will be copied out of the vector instead of borrowed (you need to explicitly borrow if you want a reference):

use std::ops::Index;

// these are equivalent
let x = vectors[0];
let x = *Index::index(&vectors, 0);

// these are equivalent
let x = &vectors[0];
let x = Index::index(&vectors, 0);
Community
  • 1
  • 1
Frxstrem
  • 38,761
  • 9
  • 79
  • 119
2

The type of the values (probably i32) in your Vec implement the Copy trait, which means that they do not get moved out when indexing the vector, they get copied instead.

A Vec of such Copy types still doesn't implement Copy itself, so it gets moved into the loop. You can avoid this e.g. by writing

for i in vectors.iter() {
    println!("Element is {}", *i);
}

The dereference (*) gives you an owned value like you'd get in your original code sample. It isn't necessary for println!, but might be necessary for other uses.

nnnmmm
  • 7,964
  • 4
  • 22
  • 41