在我的应用程序中,我获取大型对象(昂贵),并将它们存储在巨大的 HashMap 中。一旦插入地图,它们就永远不会被删除。
对象本身具有内部可变性(互斥体等),因此我从不将它们引用为可变的。这些对象被视为单例,一旦加载,应用程序中的所有位置都会引用相同的底层对象,以便更改是全局的。
伪代码,但大意是:
struct Thing {
inner: Arc<InnerThing>,
}
struct InnerThing {
field1: xxx,
field2: Vec<yyy>,
field3: Mutex<Something>,
}
struct App {
map: HashMap<key, Thing>
}
impl App {
fn get_thing(&mut self, key) -> Thing {
if let Some(val) = self.map.get(key) {
return val.clone();
}
// Load (expensive) Thing, insert into map
let thing = LoadExpensiveThing();
self.map.insert(key, thing.clone());
thing
}
}
整个应用程序中的各个位置都调用
getThing(key)
,并且所有位置都与相同的底层 Thing
进行交互。
我很想避免使用 Arc<>,因为
App.map
拥有每个 Thing 对象,并且由于用例,它们永远不会从地图中删除,但我不确定如何将其表示为借用检查员。显然我遇到了正常的“活得不够长”,因为理论上它可以从地图上删除(但不会)。我也在使用 Tokio,因此需要将这些引用传递给生成的任务(同步/发送)。
我如何告诉借用检查器,引用基本上将永远存在(基本上是“静态的”)?
我如何告诉借用检查器,引用基本上将永远存在(基本上是“静态的”)?
你不知道,因为他们不是
'static
。在生命周期问题上向编译器撒谎是导致未定义行为的绝佳方式。
仅仅因为这些项目不会从地图中删除并不意味着它们将始终存在于内存中的同一位置。将项目添加到地图可以触发重新分配,从而重新定位现有值,这将使对它们的所有现有引用无效。
Rust 在这里保护你。其他一些语言会让您这样做,从而在以后的某个时间导致未定义的行为。
只需使用
Arc
。