在嵌套循环中修改结构的 Rust 方法是什么? [英] What's the Rust way to modify a structure within nested loops?

查看:43
本文介绍了在嵌套循环中修改结构的 Rust 方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Give 是一组以某种方式相互交互的物体.作为一个新手,我接近它,就像我用其他语言做的一样:

Given is an array of bodies that interact in some way with each other. As a newbie I approached it as I would do it in some other language:

struct Body {
    x: i16,
    y: i16,
    v: i16,
}

fn main() {
    let mut bodies = Vec::<Body>::new();

    bodies.push(Body { x: 10, y: 10, v: 0 });
    bodies.push(Body { x: 20, y: 30, v: 0 });

    // keep it simple and loop only twice
    for i in 0..2 {
        println!("Turn {}", i);
        for b_outer in bodies.iter() {
            println!("x:{}, y:{}, v:{}", b_outer.x, b_outer.y, b_outer.v);
            let mut a = b_outer.v;
            for b_inner in bodies.iter() {
                // for simplicity I ignore here to continue in case b_outer == b_inner
                // just do some calculation
                a = a + b_outer.x * b_inner.x;
                println!(
                    "    x:{}, y:{}, v:{}, a:{}",
                    b_inner.x,
                    b_inner.y,
                    b_inner.v,
                    a
                );
            }
            // updating b_outer.v fails
            b_outer.v = a;
        }
    }
}

在内循环完成后更新 b_outer.v 失败:

Updating of b_outer.v after the inner loop has finished fails:

error[E0594]: cannot assign to immutable field `b_outer.v`
  --> src/main.rs:32:13
   |
32 |             b_outer.v = a;
   |             ^^^^^^^^^^^^^ cannot mutably borrow immutable field

使 b_outer 可变:

for b_outer in bodies.iter_mut() { ...

也不起作用:

error[E0502]: cannot borrow `bodies` as mutable because it is also borrowed as immutable
  --> src/main.rs:19:32
   |
16 |             for b_outer in bodies.iter() {
   |                            ------ immutable borrow occurs here
...
19 |                 for b_inner in bodies.iter_mut() {
   |                                ^^^^^^ mutable borrow occurs here
...
33 |             }
   |             - immutable borrow ends here

现在我卡住了.内循环完成后更新 b_outer.v 的 Rust 方法是什么?

Now I'm stuck. What's the Rust approach to update b_outer.v after the inner loop has finished?

推荐答案

就其价值而言,我认为错误消息告诉您您的代码存在逻辑问题.如果您在内循环的迭代之间更新向量,则这些更改将用于后续迭代.让我们看一个较小的例子,我们计算一个数组项及其邻居的窗口平均:

For what it's worth, I think the error message is telling you that your code has a logic problem. If you update the vector between iterations of the inner loop, then those changes will be used for subsequent iterations. Let's look at a smaller example where we compute the windowed-average of an array item and its neighbors:

[2, 0, 2, 0, 2] // input
[2/3, 4/3, 2/3, 4/3, 2/3] // expected output (out-of-bounds counts as 0)

[2/3, 0,      2, 0, 2] // input after round 1
[2/3, 8/9,    2, 0, 2] // input after round 2
[2/3, 8/9, 26/9, 0, 2] // input after round 3
// I got bored here

我建议将输出计算为一个临时向量,然后交换它们:

I'd suggest computing the output into a temporary vector and then swap them:

#[derive(Debug)]
struct Body {
    x: i16,
    y: i16,
    v: i16,
}

fn main() {
    let mut bodies = vec![Body { x: 10, y: 10, v: 0 }, Body { x: 20, y: 30, v: 0 }];

    for _ in 0..2 {
        let next_bodies = bodies
            .iter()
            .map(|b| {
                let next_v = bodies
                    .iter()
                    .fold(b.v, { |a, b_inner| a + b.x * b_inner.x });
                Body { v: next_v, ..*b }
            })
            .collect();
        bodies = next_bodies;
    }

    println!("{:?}", bodies);
}

输出:

[Body { x: 10, y: 10, v: 600 }, Body { x: 20, y: 30, v: 1200 }]

如果你真的关心内存性能,你可以总共创建两个向量,适当调整它们的大小,然后在两者之间交替.不过代码会更丑.

If you really concerned about memory performance, you could create a total of two vectors, size them appropriately, then alternate between the two. The code would be uglier though.

正如 Matthieu M. 所说,您可以使用 CellRefCell,它们都赋予你内部可变性:

As Matthieu M. said, you could use Cell or RefCell, which both grant you inner mutability:

use std::cell::Cell;

#[derive(Debug, Copy, Clone)]
struct Body {
    x: i16,
    y: i16,
    v: i16,
}

fn main() {
    let bodies = vec![
        Cell::new(Body { x: 10, y: 10, v: 0 }),
        Cell::new(Body { x: 20, y: 30, v: 0 }),
    ];

    for _ in 0..2 {
        for b_outer_cell in &bodies {
            let mut b_outer = b_outer_cell.get();

            let mut a = b_outer.v;
            for b_inner in &bodies {
                let b_inner = b_inner.get();
                a = a + b_outer.x * b_inner.x;
            }
            b_outer.v = a;
            b_outer_cell.set(b_outer);
        }
    }

    println!("{:?}", bodies);
}

[Cell { value: Body { x: 10, y: 10, v: 600 } }, Cell { value: Body { x: 20, y: 30, v: 1200 } }]

这篇关于在嵌套循环中修改结构的 Rust 方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆