Cannot move out of _ which is behind a shared reference

My code is like below and this is not the entire code.
The problem is about E507.
I tried to fix this problem but I couldn't

let mut map: HashMap<String, HashSet<String>> = HashMap::new();
    
fn parse_command(command: String) -> Vec<String> {
    let mut parsed:Vec<String> = Vec::new();
    for word in command.split_whitespace() {
        parsed.push(word.to_string());
    }
    parsed
}

for command in commands {
    let mut words = parse_command(command);
    let verb = words[0].as_str();
    match verb {
        "Add" => {
            let dept = words.pop().unwrap();
            let to = words.pop();
            let person = words.pop().unwrap();
            let dept_set = map.get(&dept);
            match dept_set {                     // error occurs here
                Some(&(mut t)) => {
                    t.insert(person);
                },
                None => {
                    let mut set = HashSet::new();
                    set.insert(person);
                    map.insert(dept, set);
                },
            }
        },

and the error message

error[E0507]: cannot move out of `*dept_set.0` which is behind a shared reference
    |
260 |                 match dept_set {
    |                       ^^^^^^^^
261 |                     Some(&(mut t)) => {
    |                            -----
    |                            |
    |                            data moved here
    |                            move occurs because `t` has type `HashSet<String>`, which does not implement the `Copy` trait

please help me

You just need to call get_mut instead of get on map.

Playground with full code

let dept_set = map.get_mut(&dept);
match dept_set {
    Some(t) => {
        t.insert(person);
    }
...
}

It looks like you were trying to get a mutable reference inside the pattern, but that's not what & does in patterns. It actually works like * does in normal code, removing a reference. That was why you were getting an error about moving a variable.

Essentially you were declaring a mutable binding t that moved the hash set out of dept_set, but what you wanted was just to have a mutable reference in the first place.

I really appreciate to your kind reply.
But there occurs another issue.

"Move" => {
                let to_dept = words.pop().unwrap();
                let to = words.pop();
                let from_dept = words.pop().unwrap();
                let from = words.pop();
                let person = words.pop().unwrap();
                let to_dept_set = map.get_mut(&to_dept);
                let from_dept_set = map.get_mut(&from_dept); // error occurs here
                match (to_dept_set, from_dept_set) {
                    (Some(t), Some(u)) => {
                        if u.remove(&person) {
                            t.insert(person);
                        }
                    },
                    (_, _) => (),
                }
            },

This is actually the rest of my code, so I tried to fix it just like you let me know.
and complier gave an error like below

let to_dept_set = map.get_mut(&to_dept);
    |                                   --------------------- first mutable borrow occurs here
290 |                 let from_dept_set = map.get_mut(&from_dept);
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
291 |                 match (to_dept_set, from_dept_set) {
    |                        ----------- first borrow later used here

how can I fix this problem?
I'm so sorry bothering you....

You might need get_many_mut which needs #![feature(map_many_mut)].

if let Some([t, u]) = map.get_many_mut([&to_dept, &from_dept]) {
    if u.remove(&person) {
        t.insert(person);
    }
}

playground

Edit: Or just stop using the returned value by map.get_mut before the next map.get_mut. The overlapped lifetimes in &mut HashMap causes the error you see.

if let Some(u) = map.get_mut(&from_dept) {
    let removed = u.remove(&person);
    if let Some(t) = map.get_mut(&to_dept) {
        if removed {
            t.insert(person);
        }
    }
}

In this case, the first two lines can be rewritten with a combinator:

if let Some(removed) = map.get_mut(&from_dept).map(|u| u.remove(&person)) {

Thx a lot to all of you.

You're able to use two combinators:

if let Some(t) = map
    .get_mut(&from_dept)
    .map(|u| u.remove(&person)) // stop using `&mut HashMap` here
    .and_then(|removed| if removed { map.get_mut(&to_dept) } else { None })
{
    t.insert(person);
}

the lifetimes of map.get_mut's returned value don't overlap.

If .map is integrated into .and_then, you'll run into the same lifetime problem:

error[E0499]: cannot borrow `map` as mutable more than once at a time
  --> src/lib.rs:43:15
   |
41 |   if let Some(t) = map
   |  __________________-
42 | |     .get_mut(&from_dept)
   | |________________________- first mutable borrow occurs here
43 |       .and_then(|u| if u.remove(&person) { map.get_mut(&to_dept) } else { None })
   |        -------- ^^^                        --- second borrow occurs due to use of `map` in closure
   |        |        |
   |        |        second mutable borrow occurs here
   |        first borrow later used by call
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.