从 Rust 中的全局 HashMap 获取项目的引用

Get item's reference from global HashMap in Rust

我正在尝试使用静态 HashMap 来存储一些我想在将来全局使用和修改的数据。我发现声明这样一个全局映射的某种方法是使用 lazy_static 和互斥锁来安全地共享数据。但是,当我想 return 这些对象作为参考时,我遇到了一些所有权问题,就像我在上面的代码中所做的那样:

use std::error::Error;
use std::collections::HashMap;
use std::sync::Mutex;
use super::domain::{Session, SessionRepository}; // object and trait declaration

lazy_static! {
    static ref REPOSITORY: Mutex<HashMap<String, Session>> = {
        let mut repo = HashMap::new();
        Mutex::new(repo)
    };    
}

impl SessionRepository for REPOSITORY {
    fn find(cookie: &str) -> Result<&mut Session, Box<dyn Error>> {
        let mut repo = REPOSITORY.lock()?;
        if let Some(sess) = repo.get_mut(cookie) {
            return Ok(sess);
        }

        Err("Not found".into())
    }
}

所以问题是:有什么方法可以正确地做到这一点吗? Rust 中是否存在我可以用来实现此行为的任何设计模式?

非常感谢!

你想要做的是正确地被编译器拒绝,因为如果你可以return一个引用,那么坏事就会发生。因为在函数 returns 之后,互斥锁不再被锁定,

  1. 其他一些线程可能会锁定互斥量并获得自己的会话可变引用,这违反了可变引用提供独占访问的规则。
  2. 其他一些线程可能会锁定互斥锁并从 HashMap 中删除 会话 — 现在您正在访问已释放的内存。

解决方案:每个会话都应该在其 自己的 Arc<Mutex<_>> 中。即:

lazy_static! {
    static ref REPOSITORY: Mutex<HashMap<String, Arc<Mutex<Session>>>> = {
        ...

impl SessionRepository for REPOSITORY {
    fn find(cookie: &str) -> Result<Arc<Mutex<Session>>, Box<dyn Error>> {
        let mut repo = REPOSITORY.lock()?;
        if let Some(sess) = repo.get(cookie) {
            return Ok(Arc::clone(sess));
        }
        ...
    }

Arc 允许存储库和任何线程在其上调用 find() 并因此获得自己的 Arc 引用计数的克隆来保持会话处于活动状态指针。 Mutex 允许每个会话独立变异。