Value borrowed after move - how to get the value from inside a struct

Hi! As new to the Rust language I am trying to understand the concepts, and I find it a bit difficult. I want to do something like the code below, and it mostly compiles. Except one line (marked with a comment). All I want to do is print the item count of the HashMap, basically just extract a primitive value from inside the structure. How would I do this?

use std::collections::HashMap;

fn main()
{
    let wrapper = MapWrapper::new();
    let mut filler = MapFiller::new(wrapper);
    filler.fill();

    // How to make this line compile?
    println!("{}", wrapper.map.keys().len());
}

struct MapWrapper
{
    map: HashMap<i32, i32>
}

impl MapWrapper
{
    fn new() -> Self
    {
        return MapWrapper
        {
            map: HashMap::new()
        };
    }
}

struct MapFiller
{
    map_wrapper: MapWrapper
}

impl MapFiller
{
    fn new(map_wrapper: MapWrapper) -> Self
    {
        return MapFiller
        {
            map_wrapper: map_wrapper
        }
    }

    fn fill(& mut self)
    {
        &self.map_wrapper.map.insert(1, 1);
    }
}

Hi! Could you please put your example code inside a code block (three backticks ``` on the lines just before and after) instead of a quote block? It's a lot easier to read that way.

Sure thing. Didn't find 'source code' among the formatting buttons when I wrote the question :slight_smile:

1 Like

The issue is that after the line

let mut filler = MapFiller::new(wrapper);

the MapFiller value previously referred to by wrapper is owned by filler, so you can't use wrapper to access it anymoreā€”a value can only have one owner at a time.

It's a bit difficult to tell what the best solution is in your real use case since this code is so stripped-down, but one approach would be to combine MapFiller and MapWrapper into one type that has a .fill() method and that also lets you get a reference to the inner HashMap:

struct HoldsAMap {
    map: HashMap<i32, i32>,
}

impl HoldsAMap {
    fn fill(&mut self) {
        self.map.insert(1, 1);
    }

    fn inner(&self) -> &HashMap<i32, i32> {
        &self.map
    }
}

fn main() {
    let mut holds_a_map = HoldsAMap { map: HashMap::new() };
    holds_a_map.fill();
    println!("{}", holds_a_map.inner().keys().len());
}
1 Like

Also, if you just want to see something for debugging or confirmation you could access wrapper via filler like so:

println!("{}", filler.map_wrapper.map.keys().len());
1 Like

Thanks for the explanation. Howevrer, I REALLY want them separated... Is there no way of revoking ownership? Or transfer it? After the map is filled, I just want read-only access to it.

Still confused why this is possible but not my original code, but it works for now...

To expand on the explanation above, at the start of main, wrapper owns the value created with MapWrapper::new(). In the next line, that value "moves out of" wrapper, into filler.map_wrapper (because of MapFiller::new(wrapper)). wrapper is now empty, and hence the compiler error. You need to access it through the new owner of the value, filler.map_wrapper.

1 Like

"Understanding Ownership" from The Rust Programming Language might be helpful for seeing through what's going on here.

Great, thanks for all the input!