尝试实现查找或插入时的 HashMap 借用问题 [英] HashMap borrow issue when trying to implement find or insert

查看:31
本文介绍了尝试实现查找或插入时的 HashMap 借用问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试实现自己的类似 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 时,我们将它借用到 ma​​tch 语句的作用域,所以我们不能调用 self.types.insert 在这里.我试图将方法从 None 分支移出 ma​​tch 语句,但它也失败了.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆