Borrowed vec and the Copy trait

hi guys, I am new to rust, and I just encountered a confusing problem.

fn main(){
    let mut vec = vec![1,2,3];
    foo(&mut vec);
}

fn foo(vec: &mut Vec<i32>){
    for item in vec{
        print!("{}", item);
    }
    vec.push(4);
}

In the above code snippet, the foo function. rustc said "borrowed of moved value: vec"

error[E0382]: borrow of moved value: `vec`
   --> src/main.rs:11:5
    |
7   | fn foo(vec: &mut Vec<i32>){
    |        --- move occurs because `vec` has type `&mut Vec<i32>`, which does not implement the `Copy` trait
8   |     for item in vec{
    |                 ---
    |                 |
    |                 `vec` moved due to this implicit call to `.into_iter()`
    |                 help: consider borrowing to avoid moving into the for loop: `&vec`
...
11  |     vec.push(4);
    |     ^^^ value borrowed here after move
    |
note: this function takes ownership of the receiver `self`, which moves `vec`
   --> /Users/steve/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/collect.rs:232:18
    |
232 |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^

What I know is, if you iterate over a vector, which does not implement the Copy trait, it will move. The reason why it moved is rust called a method .into_iter(), which takes the ownership of the Vec.
The confusing part about my code is the vec(parameter of funciont foo) is of type &mut Vec, not of the type Vec. The type of item(variable in the for loop of function foo) is &mut i32, as the IDEA tells me. And with the info( vec moved due to this implicit call to .into_iter()) generated by the compiler, what i should do is to call the method into_iter() explictly. Error disappears when i did this, but the type of item is still &mut i32, what is the difference? last confusing point, when I iterate the vec(&mut Vec<i32) in my code, what does the compiler do? dereferences the vec and calls into_iter()?

I am not native in English, so perhaps the expression of my issue is not clear, sorry for that.
Thanks for ur help in advance, i do appreciate that! :kissing_closed_eyes:

It can get a bit confusing when you are operating on variables of type &mut Vec<T> rather than Vec<T>. What's going on is that:

  1. Mutable references do not implement Copy, but sometimes behave like they do.
  2. The into_iter method comes from the IntoIterator trait which is implemented for both Vec<T>, &Vec<T> and &mut Vec<T>. Which implementation of the trait you use determines the behavior. Only the one for Vec<T> produces owned values.

The reason that you received an error about vec being moved is that mutable references are not Copy and it was consumed. To fix it, you could write &mut *vec. This creates a new mutable reference that points to the same thing as the original mutable reference. The language will automatically reborrow mutable references only when the target type is unique, but the target type is not unique here because for loops can loop over many different types.

As for the into_iter call, it worked because when the variable has type &mut Vec<T>, the compiler will prefer the implementation of the trait for &mut Vec<T> rather than the implementation for Vec<T>. Only the implementation for Vec<T> produces owned elements, so since you used a different implementation of IntoIterator, you got something else.

Another option is to call iter_mut. This method will behave the same no matter whether you call it on Vec<T> or &mut Vec<T> because there are not multiple different versions of it, so you always get the same one.

3 Likes

Thx for ur help! :kissing_closed_eyes:

And the reason why i use &mut Vec rather than Vec is in my original code i don't wanna the ownership move. The code snippet i uploaded is just the demo code to simulate the error situation. Thx again for ur friendly reply! :yum: