如何在同一函数中检查并插入借用的 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"))
}
我是 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"))
}