我有以下代码
fn foo(value: &String, cache: &mut HashMap<String, Vec<String>>) {
// values are inserted but never modified
cache.insert("a", vec!["b".to_string()]);
if let Some(cached_result) = cache.get(value) {
// let cached_result = cached_result.clone();
cached_result
.iter()
.for_each(|cached_value| foo(cached_value, cache));
}
}
这是我试图理解的问题的最小化且完全人为的示例。
在上面的代码中,借用检查器抱怨:
error[E0500]: closure requires unique access to `*cache` but it is already borrowed
--> src/day11.rs:8:23
|
4 | if let Some(cached_result) = cache.get(value) {
| ----- borrow occurs here
...
8 | .for_each(|cached_value| foo(cached_value, cache));
| -------- ^^^^^^^^^^^^^^ ----- second borrow occurs due to use of `*cache` in closure
| | |
| | closure construction occurs here
| first borrow later used by call
我的理解是这样的
cache
拥有其价值观的所有权cached_result
下游,因此我们无法在迭代它的同时安全地将其传递到那里问题是,在我的实际代码中,我从不修改值,我只插入到缓存中。
克隆
cached_result
解决了问题,但我不想这样做。
我应该如何构建代码,以便我可以拥有一个内部包含不可变值的可变缓存,并且能够在迭代该值时使用该缓存?
我的建议是使用原子引用计数器(
Arc
),这样就可以避免真正的克隆,而是增加对内存中相同数据点的引用计数器。
因为您实际上只是阅读,这应该足够了,并且可以避免数据克隆的性能损失。为了提高线程之间的安全性,您可以在
Mutex
中引入 Arc
,但您可能不需要它。
根据您的概念片段,代码可能如下所示:
use std::{collections::HashMap, sync::Arc};
fn foo(value: &String, cache: &mut HashMap<String, Arc<Vec<String>>>) {
// values are inserted but never modified
cache.insert("a".into(), Arc::new(vec!["b".to_string()]));
if let Some(cached_result) = cache.get(value) {
cached_result.clone()
.iter()
.for_each(|cached_value| foo(cached_value, cache));
}
}
希望这有帮助!