是否有一种优雅的解决方案可以在迭代时修改结构?

Is there an elegant solution to modifying a structure while iterating?

我正在尝试构建一个点向量,这些点在遍历它们时会发生变化:

struct Point {
    x: i16,
    y: i16,
}

fn main() {
    let mut points: Vec<Point> = vec![];
    // unsure if point is mutable
    points.push(Point { x: 10, y: 10 });
    // thus trying it explicitly
    let mut p1 = Point { x: 20, y: 20 };
    points.push(p1);

    for i in points.iter() {
        println!("{}", i.x);
        i.x = i.x + 10;
    }
}

编译时出现错误:

error[E0594]: cannot assign to immutable field `i.x`
  --> src/main.rs:16:9
   |
16 |         i.x = i.x + 10;
   |         ^^^^^^^^^^^^^^ cannot mutably borrow immutable field

据我了解 here,Rust 不允许在迭代结构时修改结构,因此出现错误。

如何优雅地修改它?如果我阅读 this answer 并正确理解,那么我会想到以下内容:

  1. 从向量中弹出项目,对其进行修改并将其推回。
  2. 创建一个临时结构,我将更改的项目推送到其中,并用循环外的临时结构替换原始结构(如何?)。

虽然我认为我可以让 (1) 工作,但我对所有这些 pop 和 push 并不是很满意(无论如何这是高性能吗?)。关于 (2),我不知道如何让它工作——如果它能工作的话。

问题:

  1. (2) 是一个解决方案吗?如果是,它会是什么样子?
  2. 还有其他解决方案吗?
  3. 不同解决方案的优点或缺点是什么,尤其是在性能方面?

您不能修改正在迭代的结构,即向量 points。但是,修改从迭代器中获取的元素是完全没有问题的,您只需要选择可变性:

for i in points.iter_mut() {

或者,使用更现代的语法:

for i in &mut points {

可变性是可选的,因为可变的迭代进一步限制了你在迭代时可以用 points 做什么。由于可变别名(即两个或多个指向同一内存的指针,其中至少一个是 &mut)是被禁止的,你甚至不能 read from pointsiter_mut() 迭代器在附近。