如何在 Rust 中对向量元素运行循环并在循环内外更改向量?

15

我刚接触Rust。 我需要在for循环之前创建一个向量。 在其上运行for循环。 更改for循环中的向量。 然后在for循环之后更改向量。

我尝试了以下代码并尝试使用不可变借用,但两者都没有起作用。

fn main() {
    let mut vec1 = vec![4, 5];
    vec1.push(6);
    for i in vec1 {
        if i % 2 == 0 {
            vec1.push(7);
        }
    }
    vec1.push(8);
    println!("vec1={:?}", vec1);
}

我希望在for循环内部和之后编译并更改向量,但它显示了这个错误信息:

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

你能解释移动为什么会发生吗?你能让它编译通过吗?


1
你不能这样做。向向量中推送一个新项可能会导致重新分配。如果你只是在向量的末尾添加项目,那么可以通过循环遍历向量索引而不是元素来解决这个问题,这样向量就不会被循环借用。 - Peter Hall
2个回答

24

你的代码有两个问题。幸运的是,只需要改变一个东西就可以解决这两个问题。这两个问题分别是:

  • for _ in vec1会将值vec1移动到循环中。这类移动和其他移动一样,意味着在循环之后该值不可访问!如果需要关于所有权和移动的复习,请阅读Rust书籍中相关章节。你可以通过for _ in &vec1迭代访问向量元素的引用。
  • 你正在尝试更改正在迭代的向量。无论你是按值(像你这样)还是按引用迭代向量,都不能在迭代时更改该向量。有很多好的理由!在你的情况下,如果在迭代时添加元素,可能会很容易导致无限循环。

要同时解决这两个问题,你可以迭代向量的索引而不是向量的元素(Playground):

let mut vec1 = vec![4, 5];
vec1.push(6);
for i in 0..vec1.len() {
    if vec1[i] % 2 == 0 {
        vec1.push(7);
    }
}
vec1.push(8);
println!("vec1={:?}", vec1);

这样,向量不会被 for 循环移动或借用,我们可以在循环期间和循环后自由地对其进行更改。此特定解决方案遍历原始向量的索引,这意味着在循环中添加的元素不会被循环迭代。这是一种良好的保护措施,以避免意外无限循环。然而,请注意,在迭代过程中从向量中删除元素等情况仍可能导致程序出错。通常情况下,独立于编程语言,在迭代集合时更改其中的元素是危险的,应该小心谨慎地进行。


在您的情况下,如果您在迭代时添加元素,则很容易出现无限循环的情况。虽然这不是禁止的原因。 1)无限循环是完全安全的。 2)即使他要删除元素,也不能导致无限循环,并且仍然被禁止。原因是它可能会导致元素重新定位,从而导致悬空引用。 - mcarton
@mcarton,我刚刚提到了两个易于理解的例子,但从未声称这是Rust工作原理的根本原因。此外,这个悬空引用问题取决于迭代器的实现方式。它可以以完全安全的方式实现,永远不会导致内存不安全。之所以不允许这样做的真正原因是因为Rust这么说 - Lukas Kalbertodt

0

你可以像这样使用循环来完成它,但要小心。(游乐场

fn main() {
    let mut vec1 = vec![4, 5];
    vec1.push(6);
    
    let mut i = 0;
    loop {
        if i >= vec1.len() { break; }
        if vec1[i] % 2 == 0 {
            vec1.push(7);
        }
        
        i += 1;
    }
    vec1.push(8);
    println!("vec1={:?}", vec1);
}

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