2
votes

I'm trying to remove an element from a vector if it existed in it:

use std::collections::HashMap;

fn test(map: HashMap<String, Vec<String>>, department: String, employee: String) {
    let &mut list = map.get(&department).unwrap();
    let index = list.iter().position(|x| x == &employee);
    match index {
        Some(i) => {
            list.remove(i);
        },
        None => {
            println!("No records of {} in {}!", &employee, &department);
        },
    }
}

I'm getting this error:

error[E0308]: mismatched types
 --> src/lib.rs:4:9
  |
4 |     let &mut list = map.get(&department).unwrap();
  |         ^^^^^^^^^   ----------------------------- this expression has type `&std::vec::Vec<std::string::String>`
  |         |
  |         types differ in mutability
  |
  = note:      expected reference `&std::vec::Vec<std::string::String>`
          found mutable reference `&mut _`

Playground

I thought I understood what the error is saying (line 170's RHS returns a immutable reference to the vector), but I'm not so sure how to resolve it. If try something like this instead:

let mut list = map.get(&department).unwrap();
let index = list.iter().position(|x| x == &employee);
match index {
    Some(i) => {
        list.remove(i);
    },
    ...
}

I then get

error[E0596]: cannot borrow `*list` as mutable, as it is behind a `&` reference
 --> src/lib.rs:8:13
  |
4 |     let mut list = map.get(&department).unwrap();
  |         -------- help: consider changing this to be a mutable reference: `&mut std::vec::Vec<std::string::String>`
...
8 |             list.remove(i);
  |             ^^^^ `list` is a `&` reference, so the data it refers to cannot be borrowed as mutable

Playground

These errors seem kind of circular to me, which makes me feel I need to rethink my design. How would I go about fixing this issue?

1

1 Answers

4
votes

get returns an immutable Option<&V> which won't let you call .remove(i). Use get_mut to get a mutable Option<&mut V>. Calling it requires that the map itself be mutable, which is a sign that we're doing the right thing.

use std::collections::HashMap;

fn test(map: &mut HashMap<String, Vec<String>>, department: String, employee: String) {
    //       ^^^^ 
    let list = map.get_mut(&department).unwrap();
    //             ^^^^^^^
    let index = list.iter().position(|x| x == &employee);
    match index {
        Some(i) => {
            list.remove(i);
        },
        None => {
            println!("No records of {} in {}!", &employee, &department);
        },
    }
}

Playground