Cannot move out of X which is behind a shared reference

Hello everyone,

I have the following code:

use std::collections::HashMap;

#[derive(Debug, Clone)]
struct Child {}

#[derive(Default)]
struct A {
    map: HashMap<String, Child>,
}

impl A {
    pub fn default() -> A {
        let mut a = A {
            map: HashMap::new(),
        };
        a.map.insert("one".to_string(), Child{});
        a
    }

    pub fn get_map(&self) -> HashMap<String, Child> {
        self.map
    }
}

fn do_something(value: Child) {
    println!("Value: {}", value);
}

fn main() {
    let a = A::default();
    let x = a.get_map();

    for (key, value) in x {
        println!("{}", key);
        do_something(value);
    }
}

Where get_map would return the hashmap of the struct and the loop in main would pass the value to a different function, possibly a 3rd-party crate that does something with the value.

Initially, i get the error:

21 |         self.map
   |         ^^^^^^^^ move occurs because `self.map` has type `std::collections::HashMap<std::string::String, Child>`, which does not implement the `Copy` trait

So what i though is that i could return a reference to the map so that it's still owned by the struct.

Updated code:

impl A {
....
    pub fn get_map(&self) -> &HashMap<String, Child> {
        &self.map
    }
}

Now i get the error:

35 |         do_something(value);
   |                      ^^^^^ expected struct `Child`, found &Child

Here, i could de-reference the value and clone it since it's clonable.

do_something((*value).clone());

However, if the Child objects were large, it seems like this could be very inefficient.

Is the above idiomatic code? If not, how would this kind of pattern be implemented idiomatically?

1 Like

Make do_something also accept a reference:

fn do_something(value: &Child) { 
     // Note: value is immutable in this scope
} 

What if do_something's signature cannot be modified. Assuming its provided by a 3rd party crate?

Depends on the implementation of do_something.

With the current signature, the designer of do_something seeks ownership of value and we have to provide it while remaining within the safety assurances of Rust.

You can explore smart pointers as a potential solution. Again, more avenues may be available depending on the actual implementation details of do_something.

In that case you have two options:

  1. .clone() the value, so that the function gets its own copy.

  2. Wrap your value in Option<Child> (or Mutex<Option<Child>>> if you have to keep shared & borrow), and use option.take() to remove your only copy and pass it to the function.

When the other function takes ownership it reserves the right to destroy that value, so you can't give it away and keep it at the same time — it could be destroyed!

3 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.