gpt4 book ai didi

rust - 改变嵌套循环内的项目

转载 作者:行者123 更新时间:2023-11-29 07:47:47 27 4
gpt4 key购买 nike

我正在尝试编写一个程序来均匀(或尽可能接近)分布球体表面的点。我试图通过在一个单位球体周围随机放置 N 个点,然后在这些点相互排斥的地方运行多个步骤来实现这一点。

问题出在点数组的循环中。下面的代码遍历每个点,然后在其中循环,再次遍历每个点并计算每个点对之间的排斥力。

for point in points.iter_mut() {
point.movement = Quaternion::identity();
for neighbour in &points {
if neighbour.id == point.id {
continue;
}
let angle = point.pos.angle(&neighbour.pos);
let axis = point.pos.cross(&neighbour.pos);
let force = -(1.0/(angle*angle)) * update_amt;
point.movement = point.movement * Quaternion::angle_axis(angle, axis);
}
}

我收到错误:

src/main.rs:71:27: 71:33 error: cannot borrow `points` as immutable because it is also borrowed as mutable
src/main.rs:71 for neighbour in &points {

和解释

the mutable borrow prevents subsequent moves, borrows, or modification of `points` until the borrow ends

我是 Rust 的新手,有 C++ 背景,我不知道如何让这种模式在 Rust 中工作。

任何对此的解决方案都将不胜感激,因为我现在完全没有想法。

最佳答案

有几种写法。

一个是你的建议,将运动分离到一个单独的向量中,因为这确保了运动值的可变借用不会强制编译器保守地禁止访问其余的避免从别名中可变借用。在 Rust 中,&mut 引用永远不能别名:如果值只能通过一条路径访问,则可以保证任何/所有突变都是内存安全的,如果有别名,则需要更多的努力(包括运行时检查) ) 以确保突变是安全的。

另一种是在外循环中使用索引:

for i in 0..points.len() {
let mut movement = Quaternion::identity();
for neighbour in &points {
if neighbour.id == points[i].id {
continue
}
// ...
movement = movement * Quaternion::angle_axis(angle, axis);
}

points[i].movement = movement
}

第三种方法是改变循环的工作方式:在考虑点与其邻居之间的交互时,同时更新点和邻居。这允许一个人“三角”迭代:点 01..n 交互,点 12..n 交互, ...(其中 n = points.len())。这可以通过编译器理解的不会别名的方式完成。

第一个必须将所有 movement 重置为 1。然后主循环由一个选择单个元素的外循环组成,然后可以“重新借用”内循环的迭代器。外层循环不能使用 for,因为 for 将取得迭代器的所有权,不过幸运的是,while let 允许人们巧妙地编写:

for point in &mut points {
point.movement = Quaternion::identity()
}
let mut iter = points.iter_mut();
while let Some(point) = iter.next() {
// this reborrows the iterator by converting back to a slice
// (with a shorter lifetime) which is coerced to an iterator
// by `for`. This then iterates over the elements after `point`
for neighbour in &mut iter[..] {
// `neighbour` is automatically distinct from `point`

let angle = point.pos.angle(&neighbour.pos);
let axis = point.pos.cross(&neighbour.pos);
let force = -(1.0 / (angle*angle)) * update_amt;
point.movement = point.movement * Quaternion::angle_axis(angle, axis);
neighbour.movement = neighbour.movement * Quaternion::angle_axis(angle, -axis);
}
}

注意。我相信 axis 必须为 neighbor 更新反转。 (我还没有编译这个,但希望它很接近。)

理论上,与目前为止的任何其他建议相比,后者提供了大约 2 倍的加速。至少,它减少了 n * (n - 1) angle, axis & force 的计算次数> 到 n * (n - 1)/2

关于rust - 改变嵌套循环内的项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29859892/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com