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

Rust 结构体中HashMap取多个可变借用触发所有权错误如何解决?

问题原因

Rust 借用检查器目前无法识别从 HashMap 中取出的多个可变引用是否指向不同元素,当你调用接收 &mut self 的 load 方法时,返回的可变引用会持有整个 Resource 实例的可变借用,在第一个可变引用的生命周期结束前,无法再获取第二个可变引用,因此直接传入两个参数会报错。

解决方案

方案1:使用标准库 get_many_mut (推荐,零运行时开销)

Rust 1.62 及以上版本的 HashMap 内置了 get_many_mut 方法,可以安全地同时获取多个不同 key 对应的可变引用,借用检查器会认可这一操作的安全性。
你可以为 Resource 新增批量加载的方法:

impl Resource {
    // 新增双key加载方法
    pub fn load_two(&mut self, key1: String, key2: String) -> (&mut String, &mut String) {
        self.map.get_many_mut([&key1, &key2]).unwrap()
    }
}

调用时直接获取两个引用传入函数即可:

let (value1, value2) = res.load_two("Item1".to_string(), "Item2".to_string());
multi_parameter(value1, value2);

如果需要同时获取更多参数,可以使用 get_many_mut 传入更长的 key 数组。

方案2:使用内部可变性适配多引用场景

如果需要更灵活的多引用获取逻辑,可以将 HashMap 的值包裹一层 RefCell,将可变借用检查从编译期转移到运行期,只要你确保获取的 key 不会重复就不会出现运行时错误,非常适合游戏资源管理这类 key 天然唯一的场景。
修改后的代码如下:

use std::cell::RefCell;
use std::collections::HashMap;

struct Resource {
    map: HashMap<String, RefCell<String>>,
}

impl Resource {
    pub fn new() -> Self {
        Resource {
            map: HashMap::new(),
        }
    }

    // load方法不再需要&mut self
    pub fn load(&self, key: String) -> RefMut<'_, String> {
        self.map.get(&key).unwrap().borrow_mut()
    }
}

// 调用逻辑不需要做太大修改
fn main() {
    let mut res = Resource::new();
    res.map.insert("Item1".to_string(), RefCell::new("Value1".to_string()));
    res.map.insert("Item2".to_string(), RefCell::new("Value2".to_string()));

    let value1 = res.load("Item1".to_string());
    let value2 = res.load("Item2".to_string());
    // 直接解引用即可传入参数,RefMut实现了DerefMut trait
    multi_parameter(&mut *value1, &mut *value2);
}

方案3:unsafe 手动保证安全性(不推荐)

如果你完全确定两个 key 永远不会重复,也可以用裸指针跳过编译期借用检查,但需要自行保证没有可变引用别名,否则会触发未定义行为:

impl Resource {
    pub unsafe fn load_unchecked(&mut self, key: String) -> *mut String {
        self.map.get_mut(&key).unwrap() as *mut String
    }
}

// 调用时手动转换为可变引用
unsafe {
    let value1 = &mut *res.load_unchecked("Item1".to_string());
    let value2 = &mut *res.load_unchecked("Item2".to_string());
    multi_parameter(value1, value2);
}
SDL2 场景适配建议

游戏开发中纹理资源的 key 通常是唯一的,优先选择方案1,不需要修改原有资源存储结构,没有额外开销。如果需要同时传入的纹理数量不固定,选择方案2即可,RefCell 的运行时开销可以忽略不计,完全满足游戏渲染的性能要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 18:15:04