我试图实现自己的模拟find_or_insert方法,如下所示:
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() {}
Run Code Online (Sandbox Code Playgroud)
错误:
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
Run Code Online (Sandbox Code Playgroud)
我知道有一些标准方法可以实现这个功能,但我希望这个方法尽可能轻 - 它会非常频繁地调用,而且几乎所有的时候都会存在这些值.
据我了解,当我们打电话时,我们将self.types.get它借到匹配声明的范围,所以我们不能self.types.insert在这里打电话.我试图将方法从None分支中移出match语句,但它也失败了.
我找到的唯一可行解决方案需要调用get两次:
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()
}
Run Code Online (Sandbox Code Playgroud)
我该如何解决这种情况?
有一些方法HashMap可以实现这些复杂的案例.最值得注意的是,对于您的情况,HashMap::entry并且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
})
}
Run Code Online (Sandbox Code Playgroud)
然而,在你的情况下,借用self内部,这是不可能的.
因此,我们转移了self.next对闭包之外的借用,因此编译器可以将其推断为不相交self.types.只有一次查找解决了问题,应该是这样.
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
})
}
Run Code Online (Sandbox Code Playgroud)