bil*_*rer 1 hashmap rust borrow-checker
我想做这样的事情:
fn some_fn() {
let mut my_map = HashMap::from([
(1, "1.0".to_string()),
(2, "2.0".to_string()),
]);
let key = 3;
let res = match my_map.get(&key) {
Some(child) => child,
None => {
let value = "3.0".to_string();
my_map.insert(key, value);
&value // HERE IT FAILS
}
};
println!("{}", res);
}
Run Code Online (Sandbox Code Playgroud)
但编译时出现错误:
error[E0597]: `value` does not live long enough
--> src/lib.rs:16:13
|
16 | &value // HERE IT FAILS
| ^^^^^^
| |
| borrowed value does not live long enough
| borrow later used here
17 | }
| - `value` dropped here while still borrowed
error[E0382]: borrow of moved value: `value`
--> src/lib.rs:16:13
|
14 | let value = "3.0".to_string();
| ----- move occurs because `value` has type `String`, which does not implement the `Copy` trait
15 | my_map.insert(key, value);
| ----- value moved here
16 | &value // HERE IT FAILS
| ^^^^^^ value borrowed here after move
Run Code Online (Sandbox Code Playgroud)
我怎样才能优雅地修复它?在我看来,复制字符串似乎不是最佳选择。
这里的问题是,您插入value
字符串然后尝试返回对它的引用,尽管它已经被移动到 HashMap 中。您真正想要的是插入值,然后获取对插入值的引用,这可能如下所示:
let res = match my_map.get(&key) {
Some(child) => child,
None => {
let value = "3.0".to_string();
my_map.insert(key, value);
my_map.get(&key).unwrap() // unwrap is guaranteed to work
}
};
Run Code Online (Sandbox Code Playgroud)
但不要这样做。它丑陋且缓慢,因为它必须在地图中查找密钥两次。Rust 有一个方便的Entry
类型,可以让你获取 a 的条目HashMap
,然后对其执行操作:
// or_insert returns the value if it exists, otherwise it inserts a default and returns it
let res = my_map.entry(key).or_insert("3.0".to_string());
Run Code Online (Sandbox Code Playgroud)
或者,如果生成默认值的操作成本很高,您可以使用or_insert_with
传递闭包:
// this won't call "3.0".to_string() unless it needs to
let res = my_map.entry(key).or_insert_with(|| "3.0".to_string());
Run Code Online (Sandbox Code Playgroud)