迭代向量的可变引用而不移动向量中的值

Erb*_* Mo 4 rust

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);
}
Run Code Online (Sandbox Code Playgroud)

我想在子函数中改变向量而不传递该向量的所有权。子函数需要迭代向量并对其进行变异。

然而,由于以下错误,上面的代码不起作用:

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;
    |                  ^^^^
Run Code Online (Sandbox Code Playgroud)

我尝试迭代可变引用的引用,但它仍然不起作用:

// no change in main function

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

我得到的错误:

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;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

那么在我的子函数中迭代该向量然后改变该向量的正确方法是什么?

谢谢!

Cha*_*man 5

通常,当您调用具有可变引用的方法时,编译器会为您重新借用该引用,就像您编写的那样&mut *reference,如为什么可变引用未移至此处?

通用参数不会被重新借用。IntoIterator::into_iter()(这就是for循环所调用的)是通用的:它需要self,实际上是self: Self,并且Self是每个特征的隐藏通用参数。

您可以看到,即使您用简单的调用替换循环,编译器仍然会出错IntoIterator::into_iter()

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

游乐场

编译器确实会为接收者执行重新借用,即使它是通用的,因此v.into_iter()也会起作用(因此也是如此for i in v.into_iter()) - 但我们(和for循环脱糖)不into_iter()使用点语法进行调用,这意味着它被视为常规函数调用,而不是作为一种方法。

现在应该很清楚了,您可以手动重新借用它&mut *v。当然,您也可以使用iter_mut().