3

我正在尝试访问静态哈希图以进行读取和写入,但我总是遇到错误:

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()
}

但是我在 get 函数上遇到错误cannot return value referencing temporary value

我试过了.cloned().clone()甚至什么都没试过,但我没能让它工作。你能帮助我吗?

4

2 回答 2

0

我尝试了 .cloned()、.clone() 甚至什么都没有尝试,但我无法让它工作。你能帮助我吗?

Option::clone所做的只是克隆底层结构,在这种情况下它是一个,所以&ModuleItem它只是克隆引用,你仍然有一个引用,你不能返回,因为你只能在持有锁时访问哈希图的内容(否则它无法工作)。

Option::cloned实际上克隆了通过引用保存的对象,但由于无法克隆 ModuleItem ,因此不会在此处编译。

首先,您必须返回 a Option<ModuleItem>,您不能返回对映射内容的引用,因为锁将在函数结束时被释放,并且您不能跨互斥边界保持对 hashmap 内容的句柄,因为它们可以去随时离开(例如,其他线程可以移动它们,甚至完全清除地图)。

然后通过派生(然后调用)或通过“手动”创建新的 ModuleItem 来Clone复制ModuleItem,例如ModuleItemOption::cloned

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但是......这很难使用,所以我不推荐它。

于 2020-06-11T13:51:49.620 回答
0

该函数get不能使用静态生命周期,因为数据不会在程序的整个生命周期内都存在(来自 Rust 书):

作为引用生命周期 'static 表示引用指向的数据在运行程序的整个生命周期内都存在。它仍然可以被强制缩短寿命。

因此,您必须返回非静态引用或HashMap. 引用是不可能的,因为MODULE_MAP.lock().unwrap()返回的 aMutexGuard是本地的,因此是一个临时变量,其中包含HashMap. 并且返回一个参考get()HashMap

由于临时值MutexGuard将在函数结束时被销毁,因此返回的引用get将指向一个临时值。

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

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()
}
于 2020-06-11T14:03:53.290 回答