这个问题在这里已有答案:
这是一个简单的程序,它在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()
?
HashMap::get()
返回Option<&V>
,你打开它,得到&V
,所以你最终得到prev
是一个指向map
内部的不可变引用。这就是为什么你有一个不可改变的借钱map
。 prev
的类型是&i32
。
要解决您的问题,您可以取消引用该引用:
let prev = *map.get(&(x - 1)).unwrap();
在这种情况下,prev的类型是i32
,它只是堆栈上的值。它没有指向map
=>你不能不可靠地借map
所以你可以在下一行可变地借map
。
如果您启用Rust 2018版本,因为non-lexical lifetimes support,您的原始代码可以正常工作。
请注意,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中自动为你做的事情几乎相同。