return 如何引用互斥量内的静态哈希图中的项目?

How can return a reference to an item in a static hashmap inside a mutex?

我正在尝试访问静态哈希图以进行读写,但我总是收到错误消息:

use std::collections::HashMap;
use std::sync::Mutex;

pub struct ModuleItem {
    pub absolute_path: String,
}

lazy_static! {
    static ref MODULE_MAP: Mutex<HashMap<i32, ModuleItem>> = Mutex::new(HashMap::new());
}

pub fn insert(identity_hash: i32, module_item: ModuleItem) {
    MODULE_MAP
        .lock()
        .unwrap()
        .insert(identity_hash, module_item);
}

pub fn get(identity_hash: i32) -> Option<&'static ModuleItem> {
    MODULE_MAP.lock().unwrap().get(&identity_hash).clone()
}

但是我在获取函数时遇到错误cannot return value referencing temporary value

我尝试使用 .cloned().clone() 甚至什么都不用,但我无法让它工作。你能帮帮我吗?

I tried with .cloned(), .clone() or even nothing but I don't manage to get it to work. Can you help me?

所有 Option::clone 所做的就是克隆底层结构,在本例中是一个 &ModuleItem 所以它只是克隆引用,你仍然有一个引用,你不能 return 因为你只有在持有锁时才能访问 hashmap 的内容(否则它无法工作)。

Option::cloned 实际上克隆了引用持有的对象,但不在这里编译,因为无法克隆 ModuleItem。

首先你必须return一个Option<ModuleItem>,你不能 return一个对地图内容的引用,因为锁正在运行在函数结束时被释放,并且您无法跨互斥边界处理 hashmap 内容,因为它们随时可能消失(例如,另一个线程可以移动它们,甚至完全清除映射)。

然后复制 ModuleItem,方法是在 ModuleItem 上派生 Clone(然后调用 Option::cloned)或创建新的 ModuleItem "by hand",例如

pub fn get(identity_hash: i32) -> Option<ModuleItem> {
    MODULE_MAP.lock().unwrap().get(&identity_hash).map(|m| 
        ModuleItem { absolute_path: m.absolute_path.clone() }
    )
}

如果您经常需要 get 键入并且担心性能,您可以随时存储 Arc<ModuleItem>。这有一些成本(因为它是一个指针,所以你的字符串现在落后于 两个 指针)但是克隆 Arc 非常便宜。

为了避免双指针,您可以将 ModuleItem 变成一个未定大小的类型并让它存储一个 str 但是......这很难使用,所以我不推荐它。

函数 get 不能使用静态生命周期,因为数据不会在程序的整个生命周期 (from the Rust book) 中存在:

As a reference lifetime 'static indicates that the data pointed to by the reference lives for the entire lifetime of the running program. It can still be coerced to a shorter lifetime.

因此您必须 return 一个 none 静态引用或 HashMap 值的副本。引用是不可能的,因为 MODULE_MAP.lock().unwrap() return 是一个 MutexGuard,它是一个本地变量,因此是一个保存 HashMap 的临时变量。并且 get()HashMap return 是一个参考。

由于临时 MutexGuard 将在函数结束时销毁,由 get 编辑的引用 return 将指向一个临时值。

要解决此问题,您可以使 ModuleItem 可克隆并 return 值的副本:

use std::collections::HashMap;
use std::sync::Mutex;

#[derive(Clone)]
pub struct ModuleItem {
    pub absolute_path: String,
}

lazy_static::lazy_static! {
    static ref MODULE_MAP: Mutex<HashMap<i32, ModuleItem>> = Mutex::new(HashMap::new());
}

pub fn insert(identity_hash: i32, module_item: ModuleItem) {
    MODULE_MAP
        .lock()
        .unwrap()
        .insert(identity_hash, module_item);
}

pub fn get(identity_hash: i32) -> Option<ModuleItem> {
    MODULE_MAP.lock().unwrap().get(&identity_hash).cloned()
}