从Rust中的全局HashMap获取项目的引用
我正在尝试使用静态 HashMap<String, Object> 来存储一些我想在未来全局使用和修改的数据。我发现声明这样一个全局映射的某种方法是使用 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 中的任何设计模式吗?
非常感谢!
回答
你试图做的事情被编译器正确地拒绝了,因为如果你可以返回一个引用,那么糟糕的事情就会发生。由于函数返回后,互斥锁不再被锁定,
- 其他一些线程可能会锁定互斥锁并获得自己对会话的可变引用,这违反了可变引用提供独占访问的规则。
- 其他一些线程可以锁定互斥锁并从 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允许独立地改变每个会话。