遍历可变向量的可变引用,而不移动向量中的值。

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);
}

我希望您能在不传递向量所有权的情况下,在子函数中改变向量。子函数需要迭代并改变向量。
然而,上述代码由于以下错误而无法工作:
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;
    |                  ^^^^

我尝试通过可变引用的引用进行迭代,但仍然无法正常工作:
// no change in main function

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

我遇到的错误信息:

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;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

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

谢谢!

2个回答

4
通常,当您使用可变引用调用方法时,编译器会为您重新借用引用,就像您编写了&mut *reference一样,如为什么可变引用在这里没有被移动?所解释的那样。
通用参数不会被重新借用。 IntoIterator::into_iter()(这是for循环调用的内容)是通用的:它采用self,实际上是self: Self,而对于每个trait,Self是一个隐藏的通用参数。
您可以看到,即使您将循环替换为对IntoIterator::into_iter()的简单调用,编译器仍然会出错。
fn go(v: &mut Vec<i32>) {
    IntoIterator::into_iter(v);
    v.push(4);
}

Playground

编译器会为接收者执行重新借用操作,即使是泛型的也一样,所以 v.into_iter() 可以工作(因此 for i in v.into_iter() 也可以),但我们(以及 for 循环展开)不使用点语法调用 into_iter(),这意味着它被视为常规函数调用而不是方法。

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


3
你可以使用 v.iter()v.iter_mut() 进行迭代。

谢谢!你知道为什么在这种情况下Rust编译器不允许我使用简单的for i in v语法吗? - Erben Mo
似乎for循环默认会使用into_iter,这将导致所有权的移动。 - mxp-xc
我的答案似乎有问题,而且使用 into_iter() 可能不是默认的选择。因为当输入是 &mut v 时,你仍然可以使用 into_iter()。还是按照上面的问题来,不要听取我的想法。 - mxp-xc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接