尝试从 RwLock return 引用,"borrowed value does not live long enough" 错误

Trying to return reference from RwLock, "borrowed value does not live long enough" Error

我最近一直在进行我的第一个 Rust 项目,但遇到了障碍。我正在使用 HashMap 映射 Strings 到 AtomicUsize 整数。 HashMapRwLock 保护以允许并发访问。我希望能够 return 引用 HashMap 中的 AtomicUsize 值,但是如果我尝试 return 这些对调用者的引用超过了 RwLockWriteGuard 我得到一个错误 borrowed value does not live long enough。我在下面复制了一个最小的例子,并将相同的例子放在 Rust playground here.

use std::collections::HashMap;
use std::sync::RwLock;
use std::sync::atomic::{AtomicUsize, Ordering};

struct Bar {
    val: AtomicUsize
}

impl Bar {
    pub fn new() -> Self {
        Bar { val: AtomicUsize::new(0) }
    }
}

struct Foo {
    map: RwLock<HashMap<String, Bar>>
}


impl Foo {
    pub fn get(&self, key: String) -> &Bar {
        self.map.write().unwrap().entry(key).or_insert(Bar::new())
    }
}

fn main() {
    let foo = Foo {map: RwLock::new(HashMap::new())};
    let bar = foo.get("key".to_string());
}

我得到的错误发生在以下行:

self.map.write().unwrap().entry(key).or_insert(Bar::new())

而且是因为借来的价值不够长寿。我读过其他一些讨论这个错误的帖子,这个 特别相关。读完之后,我可以得出结论,从互斥量 returned 得到的值的生命周期必须小于互斥量的生命周期,这似乎完全排除了我正在尝试做的事情。我明白为什么这应该是不可能的,因为如果我们有一个指向 Hashmap 的指针,而另一个将值插入到互斥锁中导致它被调整大小,那么我们将有一个悬空指针。

那么,我的问题是双重的。首先,我只是很好奇我是否正确理解了问题,或者是否还有其他原因导致我被禁止做我想做的事情?我的第二个问题是,如果没有 Box 原子整数并将它们存储在 HashMap 中,是否有另一种方法可以完成我想做的事情?这种方法似乎对我有用,因为我们可以 return 一个指向 Boxed 值的指针,该值始终有效。然而,这种方法似乎效率低下,因为它需要额外的指针间接层和额外的分配。谢谢!

你是对的,你不能 return 引用比 MutexGuard 还长的东西,因为这可能会导致悬空指针。

不过,将内容包装在 Box 中无济于事! Box 是一个拥有的指针,除了重定向之外,就引用生命周期而言,其行为类似于包含的值。毕竟,如果您 return 引用了它,其他人可能会将其从 HashMap 中删除并取消分配。

根据你想用参考做什么,我可以想到几个选项:

  1. 不是 Box 值,而是将它们包装在 Arc 中。从 HashMap 获取时,您将克隆 Arc,多个引用可以同时存在。

  2. 您还可以 return MutexGuard 以及参考资料;请参阅 ,如果您只想对值进行操作然后相对较快地删除引用,则该方法会很好用。这将保持互斥量直到您完成它。