我有以下代码,我想从 HashMap 返回引用(获取或插入新值)并且只进行一次查找。这在 Rust 中可能吗?
fn get(key: u32, map: &mut HashMap<u32, String>) -> &mut String {
match map.entry(key) {
Entry::Occupied(mut entry) => entry.get_mut(),
Entry::Vacant(entry) => {
entry.insert("Hello".into())
}
}
}
你想要这个吗?
fn get(key: u32, map: &mut HashMap<u32, String>) -> &mut String {
map.entry(key).or_insert_with(|| "Hello".into())
}
使用
Entry::get_mut()
的代码无法编译,因为 get_mut()
返回与条目关联的生命周期。您需要使用 Entry::into_mut()
来代替,它会消耗该条目并返回连接到 HashMap
的引用:
fn get(key: u32, map: &mut HashMap<u32, String>) -> &mut String {
match map.entry(key) {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => entry.insert("Hello".into()),
}
}
或者,正如另一个答案所说,您可以使用
or_insert_with()
。
虽然使用
or_insert_with()
( https://stackoverflow.com/a/73801683/8535397 ) 接受的答案在大多数情况下更为惯用,但使用 match map.entry()
和 into_mut()
( https://stackoverflow.com/a/73805068/8535397)对我有帮助,我想把这个写成答案,因为我认为在特定情况下匹配更有用,我希望这个将来很容易找到。
具体来说,使用匹配允许您在匹配语句中提前返回(或中断),这在插入可能失败并且您希望将错误传递给调用者时很有用,并且还允许您使用问号?运算符(https://doc.rust-lang.org/rust-by-example/std/result/question_mark.html)。反转示例:
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::num::ParseIntError;
fn get_parsed(
number_text: String,
cache: &mut HashMap<String, u32>
) -> Result<&mut u32, ParseIntError> {
let parsed = match cache.entry(number_text) {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
// imagine this is an expensive operation that can fail
let parsed: u32 = entry.key().parse()?;
entry.insert(parsed)
}
};
Ok(parsed)
}