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

如何解决Rust中同时可变与不可变借用的编译错误

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

你的代码触发借用错误的原因很直接:调用get_mut后拿到了hash_map的可变引用,而后续调用len()需要不可变引用——Rust的借用检查器不允许同一时间存在可变引用和不可变引用,因此报错。

以下是几种无需先获取长度再拿可变引用的处理方式:

方案1:缩小可变引用的作用域(推荐)

把长度判断移到可变引用的作用域之外,同时利用函数内唯一可变借用的特性保证长度不会变化:

use std::collections::HashMap;

struct A {
    val: i32,
    hash_map: HashMap<i32, i32>,
}

fn foo(a_obj: &mut A) {
    a_obj.val = 3;
    let k = 1;
    
    // 先检查key是否存在,避免后续无意义的长度判断
    if a_obj.hash_map.contains_key(&k) {
        // 此时获取长度,后续到get_mut之间无其他修改操作,长度不会变
        let len = a_obj.hash_map.len();
        if len > 1 {
            // 这里再获取可变引用,不会和之前的不可变借用冲突
            if let Some(val_part) = a_obj.hash_map.get_mut(&k) {
                *val_part = 0;
            }
        }
    }
}

fn main() {
    let mut a_obj = A {
        val: 0,
        hash_map: Default::default(),
    };
    
    foo(&mut a_obj);
}

这种方式虽然会两次查找key,但逻辑清晰且完全符合Rust的安全规则,适合大多数场景。

方案2:利用Entry API合并操作

如果你不想两次查找key,可以用Entry API,同时提前缓存长度:

use std::collections::HashMap;

struct A {
    val: i32,
    hash_map: HashMap<i32, i32>,
}

fn foo(a_obj: &mut A) {
    a_obj.val = 3;
    let k = 1;
    
    // 提前获取长度,同一函数内无其他修改,长度稳定
    let len = a_obj.hash_map.len();
    // 用Entry API直接定位并修改值,无需重复查找
    a_obj.hash_map.entry(k).and_modify(|v| {
        if len > 1 {
            *v = 0;
        }
    });
}

fn main() {
    let mut a_obj = A {
        val: 0,
        hash_map: Default::default(),
    };
    
    foo(&mut a_obj);
}

这里提前获取长度的操作完全安全,因为foo持有a_obj的唯一可变引用,不会有其他代码在中间修改hash_map的长度。

方案3:unsafe绕过借用检查(不推荐)

如果你确定自己能保证内存安全,可以用unsafe强制转换引用,但这种方式会绕过Rust的借用检查,容易引入潜在bug,仅作为最后手段:

use std::collections::HashMap;
use std::ptr;

struct A {
    val: i32,
    hash_map: HashMap<i32, i32>,
}

fn foo(a_obj: &mut A) {
    a_obj.val = 3;
    let k = 1;
    
    let hm = a_obj.hash_map.get_mut(&k);
    if let Some(val_part) = hm {
        // 用unsafe获取hash_map的原始指针,再转为不可变引用
        let hash_map_ptr = &a_obj.hash_map as *const HashMap<i32, i32>;
        let len = unsafe { (*hash_map_ptr).len() };
        
        if len > 1 {
            *val_part = 0;
        }
    }
}

fn main() {
    let mut a_obj = A {
        val: 0,
        hash_map: Default::default(),
    };
    
    foo(&mut a_obj);
}

除非你对Rust的内存模型有非常深入的理解,否则不建议使用这种方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 22:13:13