微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决从 Rust 中的全局 HashMap 获取项目的引用

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

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 中的任何设计模式来达到这种行为吗?

非常感谢!

解决方法

你试图做的是正确被编译器拒绝,因为如果你能返回一个引用,那么糟糕的事情就会发生。由于函数返回后,互斥锁不再被锁定,

  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 允许独立地改变每个会话。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。