How do I do insert/update of a Vec inside a HashMap


#1

I am doing the third exercise of the second edition of the Book - chapter 8.3 HashMaps - https://doc.rust-lang.org/book/second-edition/ch08-03-hash-maps.html#summary

Using a hash map and vectors, create a text interface to allow a user to add employee names to a department in a company. For example, “Add Sally to Engineering” or “Add Amir to Sales.” Then let the user retrieve a list of all people in a department or all people in the company by department, sorted alphabetically.

This is the data structure I have created for maintaining a list of employees by department.

HashMap<&str, Vec<&str>>

The key &str is going to store the names of departments. The value Vec<&str> is going to store a list of employees by a department.


Objective:

Try to find an entry in HashMap<&str, Vec<&str>> (people_by_department) by &str (department). If it does - it will push the &str (employee_name) into Vec<&str> (employees_by_department). Otherwise - it creates a new Vec<&str>.

The code:

let mut people_by_department: HashMap<&str, Vec<&str>> = HashMap::new();
let employee_name = "John";
let department = "Engineering";

match people_by_department.get(&department) {
    Some(&employees_by_department) => {
        employees_by_department.push(employee_name);
    },
    None => {
        people_by_department.insert(department, vec![employee_name]);
    }
}

Playground


This is not working. And throwing error.

error[E0596]: cannot borrow immutable local variable `employees_by_department` as mutable
  --> src/main.rs:10:9
   |
9  |     Some(&employees_by_department) => {
   |           ----------------------- consider changing this to `mut employees_by_department`
10 |         employees_by_department.push(employee_name);
   |         ^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow mutablyerror[E0596]: cannot borrow immutable local variable `employees_by_department` as mutable
  --> src/main.rs:10:9
   |
9  |     Some(&employees_by_department) => {
   |           ----------------------- consider changing this to `mut employees_by_department`
10 |         employees_by_department.push(employee_name);
   |         ^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow mutably

If I follow the help provided by the compiler, it doesn’t fixes it. It produces another problem. I think I am missing something. Need help. Thanks.


#2

Non-lexical lifetimes (NLL) will let this work, if you do your lookup with get_mut:

    match people_by_department.get_mut(&department) {
        Some(employees_by_department) => {
            employees_by_department.push(employee_name);
        },
        None => {
            people_by_department.insert(department, vec![employee_name]);
        }
    }

This needs a nightly compiler and #![feature(nll)] at the top of your crate, since NLL isn’t stable yet.

But this scenario is also the sort of thing that the entry API was designed for:

    people_by_department.entry(&department)
        .or_insert_with(Vec::new)
        .push(employee_name);

#3

BTW, in real-world Rust code HashMap<&str> is rarely used, e.g. only for temporary reshuffling of data that will be discarded before end of the function. 99% of the time HashMap<String> is used to actually keep the data.