我正在尝试在Rust中做一些记笔记,并且违反了借阅检查器。
fn calc_deps(cache: &mut HashMap<String, String>, key: &String) -> String {
if let Some(v) = cache.get(key) {
v
} else {
let r = /* computations */
cache.insert(key.clone(),r.clone());
r
}
}
我被告知缓存被借用了两次。如果我在插入之前就完成了对get的操作,为什么会出现问题?我有办法对这些信息进行编码吗?
答案 0 :(得分:3)
问题在于,v
的生存期是整个if/else
块的有效期,即使else
部分中不可用。您可以借助Option::cloned
来解决此问题。
pub fn calc_deps(cache: &mut HashMap<String, String>, key: &String) -> String {
if let Some(v) = cache.get(key).cloned() {
v
} else {
let r = String::from("computations");
cache.insert(key.clone(), r.clone());
r
}
}
Option::cloned
通过克隆内容将Option<&T>
映射到Option<T>
。因此,现在v
变成了String
而不是&String
,并且不再借用cache
。
另一种选择是使用HashMap::entry/or_insert_with
界面。可能更惯用了,但是它需要无条件地克隆key
。
pub fn calc_deps(cache: &mut HashMap<String, String>, key: String) -> String {
cache
.entry(key)
.or_insert_with(|| String::from("computations"))
.clone()
}
您也可以简单地使用or_insert
而不是or_insert_with
,但这将需要无条件地为r
进行计算。
pub fn calc_deps(cache: &mut HashMap<String, String>, key: String) -> String {
cache
.entry(key)
.or_insert(String::from("computations"))
.clone()
}