这是一个简单的程序,它在map
中查找先前的值并将新值放入其中。它不会编译,因为第一个查询不可变地借用了map
,而insert
想要不可变地借用了map
。
use std::collections::HashMap;
fn main() {
let mut map: HashMap<i32, i32> = HashMap::new();
map.insert(0, 0);
(1..5).for_each(|x| {
let prev = map.get(&(x - 1)).unwrap();
map.insert(x, (prev + 1) * 10);
});
map.iter().for_each(|(k, v)| println!("{} -> {}", k, v));
}
可以通过使用clone()
作为prev
来解决问题
let prev = map.get(&(x - 1)).unwrap().clone();
并获得以下输出:
0 -> 0
1 -> 10
2 -> 110
3 -> 1110
4 -> 11110
该怎么办才能不使用clone()
?
答案 0 :(得分:2)
HashMap::get()
返回Option<&V>
,您将其解开,得到&V
,因此最终得到prev
是指向map
内部的不变引用。这就是为什么您拥有map
不变的借用的原因。 prev
的类型为&i32
。
要解决您的问题,您可以取消引用该引用:
let prev = *map.get(&(x - 1)).unwrap();
在这种情况下,上一个的类型为i32
,它只是堆栈上的一个值。它不会指向map
=>内部,您不会一成不变地借用map
,因此可以在下一行中一无所用地借用map
。
由于non-lexical lifetimes support,如果启用Rust 2018版,您的原始代码就可以正常工作。
请注意,HashMap
未排序,因此输出行以任意顺序产生。如果需要排序,可以考虑使用BTreeMap
。
如果您根本不想使用Copy
(通过*
)或Clone
,并且不想切换到Rust 2018,则可以执行以下操作:
let value_to_insert = {
let prev = map.get(&(x - 1)).unwrap();
(prev + 1) * 10
}
map.insert(x, value_to_insert)
这与非词汇生命周期在Rust 2018中会自动为您完成的事情一样。