How to update HashMap (lifetimes)?

I need to get or insert a value in HashMap. Straightforward implementation (below) has lifetime conflict between borrowing mutably and immutably. I have found a similar discussion in this forum where withoutboats explained that borrow checker does not understand early returns, so I think I understand the problem, but I can not figure out solution :frowning:

I can not use HashMap::entry().or_insert_with() because it requires FnOnce() -> V whereas I have FnOnce() -> Result<V> and if value function fails, I want to return the error. It almost feels I need HashMap::entry().or_MAYBE_insert_with()

use std::collections::HashMap;
use std::io::Error;
use futures::io::ErrorKind;

fn main() {}

fn get_or_update(key: u32, map: &mut HashMap<u32, String>) -> Result<&String, Error> {
    if let Some(v) = map.get(&key) {
        return Ok(v);
    }

    if let Ok(val) = get_value() {
        map.insert(key, val);
    }

    Err(Error::from(ErrorKind::Other))
}

fn get_value() -> Result<String, Error> {
    unimplemented!()
}
error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
  --> src/main.rs:13:9
   |
7  | fn get_or_update(key: u32, map: &mut HashMap<u32, String>) -> Result<&String, Error> {
   |                                 - let's call the lifetime of this reference `'1`
8  |     if let Some(v) = map.get(&key) {
   |                      --- immutable borrow occurs here
9  |         return Ok(v);
   |                ----- returning this value requires that `*map` is borrowed for `'1`
...
13 |         map.insert(key, val);
   |         ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

Use HashMap::entry()

fn get_or_update(key: u32, map: &mut HashMap<u32, String>) -> Result<&str, Error> {
    use std::collections::hash_map::Entry;

    Ok(match map.entry(key) {
        Entry::Occupied(entry) => entry.into_mut(),
        Entry::Vacant(entry) => entry.insert(get_value()?),
    })
}
3 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.