Mutating a vec inside a map

Hello,

I have a HashMap that has a string key, and a value, that is a Vec. I would like to either add a value to the list if the key exists, or add a new entry if it does not. I wrote something like this:

fn book_reviews(mut map: HashMap<String, Vec<String>>, book: String, review: String) {
    match map.get(&book) {
        Some(list) => {list.push(review)}
        None => {map.insert(book, vec![review]);}
    }
}

I get an error as the inner list is non-mutable:

error[E0596]: cannot borrow `*list` as mutable, as it is behind a `&` reference
  --> src\main.rs:56:24
   |
56 |         Some(list) => {list.push(review)}
   |              ----      ^^^^ `list` is a `&` reference, so the data it refers to cannot be borrowed as mutable
   |              |
   |              help: consider changing this to be a mutable reference: `&mut std::vec::Vec<std::string::String>`

Is there a way to do this?

Thanks

You need map.get_mut

[edit]

Yep, that'll do it:

fn book_reviews(mut map: HashMap<String, Vec<String>>, book: String, review: String) {
    match map.get_mut(&book) {
        Some(list) => {list.push(review)}
        None => {map.insert(book, vec![review]);}
    }
}

Basically, map.get is a function from &HashMap<K, V>, &K to Option<&V>. map.get_mut is a function from &mut HashMap<K, V>, &K to Option<&mut V>. You need that to get a mutable reference to the vec, instead of an immutable reference to the vec. Then, you can mutate the vec through the mutable reference to the vec.

1 Like

You should probably use the Entry API for this though.

map.entry(&book)
    .or_default()
    .push(review);
6 Likes

That is very cool! Thanks.