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.

You should probably use the Entry API for this though.

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

That is very cool! Thanks.