给定的是一系列以彼此某种方式相互作用的物体。作为一个新手我接触它,因为我会用其他语言来做:
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
失败:
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
现在我被卡住了。在内循环结束后,Rust更新b_outer.v
的方法是什么?
答案 0 :(得分:4)
对于它的价值,我认为错误消息告诉您代码存在逻辑问题。如果在内循环的迭代之间更新向量,则这些更改将用于后续迭代。让我们看一个较小的例子,我们计算一个数组项及其邻居的窗口平均值:
[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 }]
如果你真的关心内存性能,你可以创建总共两个向量,适当地调整它们的大小,然后在两者之间交替。但代码会更加丑陋。
正如Matthieu M.所说,你可以使用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 } }]
答案 1 :(得分:2)
我知道这个问题就像是2岁,但我很好奇。
这个C#程序产生原始的所需输出:
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);
}
}
它产生的输出与上面的C#程序相同。 “缺点”是,只要您想使用v
,就需要使用get()
或into_inner()
。可能还有其他缺点我不知道。
答案 2 :(得分:1)
我决定将结构拆分为一个用作内部循环(b_inner
)中计算(输入)的基础的结构,以及收集结果(输出)的结构。内循环结束后,输入结构在外循环(b_outer
)中更新,计算从下一个主体开始。
现在不太好,以至于我必须处理两个结构,而你却没有从声明中看到它们之间的关系。
#[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);
}
输出:
[Body { x: 10, y: 10 }, Body { x: 20, y: 30 }]