What is the rust method for changing the structure inside nested loops?

This is an array of bodies that somehow interact with each other. As a beginner, I approached him the way I would have done it in another 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;
        }
    }
}

The update b_outer.vafter the completion of the inner loop is completed:

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

The creation is b_outermutable:

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

doesn't work either:

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

Now i'm stuck. What is the Rust approach updated b_outer.vafter the completion of the inner loop?

+4
source share
3 answers

, , , . , . , :

[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

:

#[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 }]

, , , . .


., Cell RefCell, :

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 i in 0..2 {
        println!("Turn {}", i);
        for b_outer_cell in &bodies {
            let mut b_outer = b_outer_cell.get();
            println!("{:?}", b_outer);

            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;
                println!("{:?}, a: {}", b_inner, a);
            }
            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 } }]
+3

, 2 , .

# :

var bodies = new[] { new Body { X = 10, Y = 10, V = 0 },
                     new Body { X = 20, Y = 30, V = 0 } };

for (int i = 0; i < 2; i++)
{
    Console.WriteLine("Turn {0}", i);

    foreach (var bOuter in bodies)
    {
        Console.WriteLine("x:{0}, y:{1}, v:{2}", bOuter.X, bOuter.Y, bOuter.V);
        var a = bOuter.V;
        foreach (var bInner in bodies)
        {
            a = a + bOuter.X * bInner.X;
            Console.WriteLine("    x:{0}, y:{1}, v:{2}, a:{3}", bInner.X, bInner.Y, bInner.V, a);
        }
        bOuter.V = a;
    }
}

v - , - :

struct Body {
    x: i16,
    y: i16,
    v: Cell<i16>,
}

v, :

// keep it simple and loop only twice
for i in 0..2 {
    println!("Turn {}", i);
    for b_outer in bodies.iter() {

        let mut a = b_outer.v.get();

        println!("x:{}, y:{}, v:{}", b_outer.x, b_outer.y, a);
        for b_inner in bodies.iter() {

            a = a + (b_outer.x * b_inner.x);

            println!(
                "    x:{}, y:{}, v:{}, a:{}",
                b_inner.x,
                b_inner.y,
                b_inner.v.get(),
                a
            );
        }

        b_outer.v.set(a);
    }
}

, # . "" , , v, get() into_inner(). , .

+2

I decided to split the structure into one, which is used as a base for calculating (input) in the inner loop ( b_inner) and one that collects the results (output). After completion of the inner loop, the input structure is updated in the outer loop ( b_outer), and the calculation begins with the next body.

What is now not so pleasant, that I have to deal with two structures, and you do not see their relationship from the declaration.

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

struct Velocity {
    vx: i16,
}

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

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

    // keep it simple and loop only twice
    for i in 0..2 {
        println!("Turn {}", i);
        for (i, b_outer) in bodies.iter().enumerate() {
            println!("x:{}, y:{}, v:{}", b_outer.x, b_outer.y, velocities[i].vx);
            let v = velocities.get_mut(i).unwrap();
            let mut a = v.vx;
            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, v.vx, a);
            }
            v.vx = a;
        }
    }

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

Conclusion:

[Body { x: 10, y: 10 }, Body { x: 20, y: 30 }]
+1
source

All Articles