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

    go(&mut v);

    // still need v here, so I can't pass ownership to the "go' method above
    println!("{}", v.len())
}

fn go(v: &mut Vec<i32>) {
    for i in v {
        println!("{}", i);
    }
    v.push(4);
}

I want to mutate a vector in a child function without passing the ownership of that vector. The child function needs to iterate the vector and mutate it.

However the code above does not work due to the following error:

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

I tried iterating through the reference of the mutable reference and it still does not work:

// no change in main function

fn go(v: &mut Vec<i32>) {
    for i in &v {
        println!("{}", i);
    }
    v.push(4);
}

error I got:

error[E0277]: `&&mut Vec<i32>` is not an iterator
   --> src/main.rs:11:14
    |
11  |     for i in &v {
    |              ^^ `&&mut Vec<i32>` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `&&mut Vec<i32>`
    = note: required because of the requirements on the impl of `IntoIterator` for `&&mut Vec<i32>`
note: required by `into_iter`
   --> /Users/moerben/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/collect.rs:234:5
    |
234 |     fn into_iter(self) -> Self::IntoIter;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

So what is the correct way to iterate through that vector in my child function and then mutate the vector?

Thanks!

Erben Mo
  • 3,528
  • 3
  • 19
  • 32

2 Answers2

4

Usually, when you call a method with a mutable reference, the compiler reborrows the reference for you, like you've written &mut *reference, as explained in Why is the mutable reference not moved here?.

Generic arguments are not reborrowed. IntoIterator::into_iter() (which is what the for loop calls) is generic: it takes self, which is actually self: Self, and Self is a hidden generic parameter for every trait.

You can see that the compiler still errs even if you replace the loop with a simple call to IntoIterator::into_iter():

fn go(v: &mut Vec<i32>) {
    IntoIterator::into_iter(v);
    v.push(4);
}

Playground.

The compiler does perform reborrowing for the receiver, even if it's generic, so v.into_iter() will work (and thus for i in v.into_iter(), too) - but we (and the for loop desugaring) do not call into_iter() with the dot syntax, meaning it's treated as a regular function call and not as a method.

Now it should be clear that you can reborrow it manually &mut *v. Of course, you can also use iter_mut().

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
3

You can use for i in v.iter() or v.iter_mut()

mxp-xc
  • 456
  • 2
  • 6
  • thanks! do you know why is Rust compiler not allowing me to use the simple ```for i in v``` syntax in this case? – Erben Mo Dec 21 '21 at 02:39
  • It seems that the for loop will use `into_iter` by default, which will cause ownership to move. https://stackoverflow.com/questions/34733811/what-is-the-difference-between-iter-and-into-iter – mxp-xc Dec 21 '21 at 02:48
  • My answer seems to be problematic, and it may not only be the default to use `into_iter()`. Because when the input is `&mut v`, you can still use `into_iter()`. Still follow the above questions, don’t listen to my thoughts. – mxp-xc Dec 21 '21 at 02:55