You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust for循环内借用冲突:cartesian_system_test_2运行失败的解决建议

解决Rust中可变/不可变借用冲突问题

问题背景

两段逻辑一致的测试代码,cartesian_system_test_1()可正常运行,而使用for循环的cartesian_system_test_2()因Rust借用检查机制报错,核心区别仅为手动逐个处理与循环处理的实现方式。

测试源代码

#[cfg(test)]
mod cartesian_system_test {
    use bioshell_cartesians::{CartesianSystem, Coordinates, NbList, PolymerRules};
    use bioshell_numerical::Vec3;

    fn do_modify_vector(vec: &mut Vec3)
    {
        vec.x = 0.0;
        vec.y = 0.0;
        vec.z = 0.0;
    }

    #[test]
    fn cartesian_system_test_1() {
        const E_TO: f64 = 6.0;
        let buffer_thickness = 4.0;
        let nbl: NbList = NbList::new(E_TO, buffer_thickness, Box::new(PolymerRules {}));
        let mut coords = Coordinates::new(3);//create a coordinate of length: 5.
        coords.add(0, 1.0,1.0,1.0);
        coords.add(1, 2.0,2.0,2.0);
        coords.add(2, 3.0,3.0,3.0);

        let mut system: CartesianSystem = CartesianSystem::new(coords, nbl);

        let mut system_coords = system.coordinates();

        assert_eq!(system.coordinates()[0], Vec3::new(1.0, 1.0, 1.0));
        assert_eq!(system.coordinates()[1], Vec3::new(2.0, 2.0, 2.0));
        assert_eq!(system.coordinates()[2], Vec3::new(3.0, 3.0, 3.0));

        let mut vec_0 = system_coords[0].clone();
        let mut vec_1 = system_coords[1].clone();
        let mut vec_2 = system_coords[2].clone();

        do_modify_vector(&mut vec_0);
        do_modify_vector(&mut vec_1);
        do_modify_vector(&mut vec_2);

        system.set_vec(0, vec_0);
        system.set_vec(1, vec_1);
        system.set_vec(2, vec_2);

        assert_eq!(system.coordinates()[0], Vec3::new(0.0, 0.0, 0.0));
        assert_eq!(system.coordinates()[1], Vec3::new(0.0, 0.0, 0.0));
        assert_eq!(system.coordinates()[2], Vec3::new(0.0, 0.0, 0.0));
    }

    #[test]
    fn cartesian_system_test_2() {
        const E_TO: f64 = 6.0;
        let buffer_thickness = 4.0;
        let nbl: NbList = NbList::new(E_TO, buffer_thickness, Box::new(PolymerRules {}));
        let mut coords = Coordinates::new(3);
        coords.add(0, 1.0,1.0,1.0);
        coords.add(1, 2.0,2.0,2.0);
        coords.add(2, 3.0,3.0,3.0);

        let mut system: CartesianSystem = CartesianSystem::new(coords, nbl);

        let mut system_coords = system.coordinates();

        assert_eq!(system.coordinates()[0], Vec3::new(1.0, 1.0, 1.0));
        assert_eq!(system.coordinates()[1], Vec3::new(2.0, 2.0, 2.0));
        assert_eq!(system.coordinates()[2], Vec3::new(3.0, 3.0, 3.0));

        for i in 0..3{
            let mut vec = system_coords[i].clone();
            do_modify_vector(&mut vec);
            system.set_vec(i, vec);
        }

        assert_eq!(system.coordinates()[0], Vec3::new(0.0, 0.0, 0.0));
        assert_eq!(system.coordinates()[1], Vec3::new(0.0, 0.0, 0.0));
        assert_eq!(system.coordinates()[2], Vec3::new(0.0, 0.0, 0.0));
    }
}

报错信息

error[E0502]: cannot borrow `system` as mutable because it is also borrowed as immutable
  --> bioshell-cartesians\tests\test_cartesian_system.rs:69:13
   |
60 |         let mut system_coords = system.coordinates();
   |                                 -------------------- immutable borrow occurs here
...
67 |             let mut vec = system_coords[i].clone();
   |                           ------------- immutable borrow later used here
68 |             do_modify_vector(&mut vec);
69 |             system.set_vec(i, vec);
   |             ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

解决方案

方案1:移除长期不可变借用,循环内直接获取坐标

问题根源是system_coords持有了system的不可变引用,且在整个循环周期内持续有效,导致无法同时进行可变借用。修改循环部分,直接从system获取坐标克隆,避免持有长期引用:

// 移除提前声明的system_coords变量
// let mut system_coords = system.coordinates();

assert_eq!(system.coordinates()[0], Vec3::new(1.0, 1.0, 1.0));
assert_eq!(system.coordinates()[1], Vec3::new(2.0, 2.0, 2.0));
assert_eq!(system.coordinates()[2], Vec3::new(3.0, 3.0, 3.0));

for i in 0..3{
    // 每次循环直接从system获取坐标并克隆,借用仅在当前迭代有效
    let mut vec = system.coordinates()[i].clone();
    do_modify_vector(&mut vec);
    system.set_vec(i, vec);
}

方案2:提前克隆所有坐标,释放不可变借用

先一次性克隆所有坐标到临时向量,此时system的不可变借用会立即释放,后续循环仅操作临时向量,再批量设置回system:

// 提前克隆所有坐标,完成后system的不可变借用自动释放
let mut coords_clone: Vec<Vec3> = system.coordinates().iter().cloned().collect();

assert_eq!(system.coordinates()[0], Vec3::new(1.0, 1.0, 1.0));
assert_eq!(system.coordinates()[1], Vec3::new(2.0, 2.0, 2.0));
assert_eq!(system.coordinates()[2], Vec3::new(3.0, 3.0, 3.0));

for i in 0..3{
    do_modify_vector(&mut coords_clone[i]);
    system.set_vec(i, coords_clone[i].clone());
}

方案3:修改CartesianSystem提供可变访问接口(若有权限)

如果可以修改CartesianSystem的实现,添加返回可变引用的方法(如coordinates_mut),直接修改内部坐标,无需克隆和调用set_vec:

// 假设CartesianSystem新增如下方法:
// fn coordinates_mut(&mut self) -> &mut [Vec3] {
//     // 返回内部坐标的可变切片
// }

// 循环内直接修改
for vec in system.coordinates_mut() {
    do_modify_vector(vec);
}

原因说明

Rust借用检查器禁止同一对象同时存在可变引用和不可变引用。cartesian_system_test_1()中,克隆完所有向量后,system_coords的不可变引用不再被使用,借用检查器允许后续的可变借用;而cartesian_system_test_2()中,system_coords在每次循环迭代都被访问,不可变引用持续存活,此时调用system.set_vec(需要可变引用)就会触发冲突。

内容的提问来源于stack exchange,提问作者user366312

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 19:19:56