小能豆

如何高效地从 HashMap 中查找和插入?

rust

我想做以下事情:

  • 查找Vec某个键,并将其存储以供以后使用。
  • 如果不存在,Vec则为该键创建一个空值,但仍将其保留在变量中。

如何有效地做到这一点?我自然认为我可以使用match

use std::collections::HashMap;

// This code doesn't compile.
let mut map = HashMap::new();
let key = "foo";
let values: &Vec<isize> = match map.get(key) {
    Some(v) => v,
    None => {
        let default: Vec<isize> = Vec::new();
        map.insert(key, default);
        &default
    }
};

当我尝试时,它给了我这样的错误:

error[E0502]: cannot borrow `map` as mutable because it is also borrowed as immutable
  --> src/main.rs:11:13
   |
7  |     let values: &Vec<isize> = match map.get(key) {
   |                                     --- immutable borrow occurs here
...
11 |             map.insert(key, default);
   |             ^^^ mutable borrow occurs here
...
15 | }
   | - immutable borrow ends here

我最终做了这样的事情,但我不喜欢它执行两次查找(map.contains_keymap.get):

// This code does compile.
let mut map = HashMap::new();
let key = "foo";
if !map.contains_key(key) {
    let default: Vec<isize> = Vec::new();
    map.insert(key, default);
}
let values: &Vec<isize> = match map.get(key) {
    Some(v) => v,
    None => {
        panic!("impossiburu!");
    }
};

有没有一种安全的方法可以只用一个来做到这一点match


阅读 67

收藏
2024-05-21

共1个答案

小能豆

您可以使用entry提供的 API来实现您的目标HashMap。该entry方法允许您在键不存在时插入一个值,并返回对该值的可变引用,或者如果键存在则返回对现有值的可变引用。这避免了多次查找的需要并确保安全的可变借用。

以下是使用 API 重写代码的方法entry

锈复制代码use std::collections::HashMap;

let mut map = HashMap::new();
let key = "foo";

let values: &Vec<isize> = match map.entry(key) {
    std::collections::hash_map::Entry::Occupied(entry) => entry.into_mut(),
    std::collections::hash_map::Entry::Vacant(entry) => entry.insert(Vec::new()),
};

在此代码中:

  • map.entry(key)返回一个枚举变量,表示该键是被占用还是空闲。
  • 如果该键被占用,entry.into_mut()则返回对现有值的可变引用。
  • 如果键为空,entry.insert(Vec::new())则将一个新的空向量插入到映射中并返回对其的可变引用。

这样,您只需执行一次查找即可安全高效地实现您的目标。

2024-05-21