尝试实现查找或插入时的 HashMap 借用问题 [英] HashMap borrow issue when trying to implement find or insert
问题描述
我尝试实现自己的类似 find_or_insert
方法,如下所示:
I tried to implement own analogue of find_or_insert
method that looks like this:
use std::collections::HashMap;
pub struct SomeManager {
next: i32,
types: HashMap<i32, i32>,
}
impl SomeManager {
pub fn get_type<'a>(&'a mut self, k: i32) -> &'a i32 {
match self.types.get(&k) {
Some(ref x) => return *x,
None => {
self.types.insert(k, self.next);
self.next += 1;
return self.types.get(&k).unwrap();
}
}
}
}
fn main() {}
错误:
error[E0502]: cannot borrow `self.types` as mutable because it is also borrowed as immutable
--> src/main.rs:13:17
|
10 | match self.types.get(&k) {
| ---------- immutable borrow occurs here
...
13 | self.types.insert(k, self.next);
| ^^^^^^^^^^ mutable borrow occurs here
...
18 | }
| - immutable borrow ends here
我知道有一些标准方法可以实现此功能,但我希望此方法尽可能轻巧 - 它会被非常频繁地调用,并且几乎所有时间值都已经存在.
I know that there are some standard methods that implement this functionality, but I want this method to be as light as possible - it will be called very-very often and almost all of the time the values will already exist.
据我所知,当我们调用 self.types.get
时,我们将它借用到 match 语句的作用域,所以我们不能调用 self.types.insert
在这里.我试图将方法从 None 分支移出 match 语句,但它也失败了.
As I understand it, when we call self.types.get
we borrow it to scope of match statement, so we can't call self.types.insert
here. I have tried to move methods from None branch out of match statement, but it also fails.
我发现的唯一可行的解决方案需要调用 get
两次:
The only working solution that I found requires invoking get
twice:
pub fn get_type<'a>(&'a mut self, k: i32) -> &'a i32 {
let is_none = match self.types.get(&k) {
Some(ref x) => false,
None => true,
};
if is_none {
self.types.insert(k, self.next);
self.next += 1;
}
self.types.get(&k).unwrap()
}
我该如何解决这种情况?
How can I work around such situations?
推荐答案
HashMap
上有一些方法可以实现这些复杂的情况.最值得注意的是,对于您的情况,HashMap::entry
和 <代码>条目::or_insert_with:
There are a handful of methods on HashMap
to achieve these sorts of complex cases. Most notably, for your case, HashMap::entry
and Entry::or_insert_with
:
pub fn get_type<'a>(&'a mut self, k: i32) -> &'a i32 {
self.types.entry(k).or_insert_with(|| {
let value = self.next;
self.next += 1;
value
})
}
然而,在你的情况下,里面有 self
的借用,所以这行不通.
In your case, however, there’s the borrow of self
inside, so that won’t do.
因此,我们将 self.next
的借用移到闭包之外,以便编译器可以将其推断为与 self.types
不相交.只需一次查找即可解决问题,这是应该的.
We thus shift the borrow of self.next
outside of the closure so the compiler can reason about it as disjoint from self.types
. Problem solved with only one lookup, as it should be.
pub fn get_type<'a>(&'a mut self, k: i32) -> &'a i32 {
let next = &mut self.next;
self.types.entry(k).or_insert_with(|| {
let value = *next;
*next += 1;
value
})
}
这篇关于尝试实现查找或插入时的 HashMap 借用问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!