如何在同一函数中检查并插入借用的 Hashmap?

How do I check and insert into a borrowed Hashmap in the same function?

我是 Rust 的新手。我已经实现了一个 hashmap 来缓存数据库中的对象。我有一个函数来定位检查 hashmap 的对象,如果它不存在,则从数据库中检索并插入 hashmap 以供将来使用。我希望 locate 函数 return 对 hashmap 中对象的引用,以便可以使用它。以下是使用水果的问题示例:

use std::collections::HashMap;

fn main() {
    let mut fruit: HashMap<u16, String> = HashMap::new();

    fruit.insert(1, String::from("apple"));
    fruit.insert(7, String::from("banana"));
    fruit.insert(13, String::from("cherry"));

    println!("Fruit 7 is {}", locate_fruit(&mut fruit, 7).unwrap());
    println!("Fruit 15 is {}", locate_fruit(&mut fruit, 15).unwrap());
}

fn locate_fruit(fruit: &mut HashMap<u16, String>, fruit_id: u16) -> Option<&String> {

    if let Some(fruit_name) = fruit.get(&fruit_id) {
        return Some(fruit_name);
    }

    // in real code, get new_fruit from database
    let new_fruit = String::from("new fruit");

    fruit.insert(fruit_id, new_fruit);

    fruit.get(&fruit_id)
}

编译器抱怨:cannot borrow '*fruit' as mutable because it is also borrowed as immutable 用于 fruit.insert 行,因为一旦我已经有了一个不可变引用,我就无法创建一个可变引用。我试过如下使用生命周期注解:

fn locate_fruit<'a>(fruit: &'a mut HashMap<u16, String>, fruit_id: u16) -> Option<&'a String>

但这并不能解决问题。我需要以某种方式告诉编译器它可以删除在第一个 fruit.get() 调用中进行的引用。感谢任何帮助!

(我还需要在最后再次调用 fruit.get() 吗,或者我能否以某种方式将对 new_fruit 的引用传递回去?例如 Some(&new_fruit)

我的首选方法是先检查地图是否包含该值,如果不包含,则将其插入。这主要是因为它感觉更直观。它也不需要像 .entry(x) 这样的地图密钥的拥有版本。

fn locate_fruit(fruit: &mut HashMap<u16, String>, fruit_id: u16) -> Option<&String> {
    if !fruit.contains_key(&fruit_id) {
        fruit.insert(fruit_id, String::from("new fruit"));
    }

    fruit.get(&fruit_id)
}

但是,如果条目尚不存在,您可以通过获取条目并填充它来获得更好的性能。此方法使用闭包,因此仅在需要时才创建要插入的值。或者,也可以使用 .or_insert(String::from("new fruit")),但它会在每次调用时分配(并可能立即释放)一个新字符串。

fn locate_fruit(fruit: &mut HashMap<u16, String>, fruit_id: u16) -> &str {
    fruit.entry(fruit_id).or_insert_with(||String::from("new fruit"))
}