0

I am working on a project where I instantiate a parent struct, do some work based on the input, and build its child struct. In my implementation it contains metadata utilized for the parent struct's functionality, so I access the child struct immediately with unwrap which causes a partial move of the parent's value, making it impossible to return. See the minimal example code:

pub struct ParentStruct {
    child: Option<ChildStruct>
}

struct ChildStruct {
    value: String
}

impl ParentStruct {
    pub fn new() -> ParentStruct {
        let mut parent = ParentStruct {
            child: None
        };

        // After this, parent has child property
        parent.build_child();

        let child = parent.child.unwrap();

        // Use child's values in some operation
        println!("Printing child's value: {:?}", child.value);

        // Reassigning child presumably "puts it back"--is this correct?
        // parent.child = Some(child);

        // Without previous line, this errors
        parent
    }

    fn build_child(&mut self) {
        let child = ChildStruct {
            value: String::from("child created")
        };
        self.child = Some(child);
    }
}

This causes the following error:

error[E0382]: use of partially moved value: `parent`
   --> src/main.rs:52:9
    |
43  |         let child = parent.child.unwrap();
    |                                  -------- `parent.child` partially moved due to this method call
...
52  |         parent
    |         ^^^^^^ value used here after partial move
    |
note: this function takes ownership of the receiver `self`, which moves `parent.child`
   --> /Users/way/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:383:25
    |
383 |     pub const fn unwrap(self) -> T {
    |                         ^^^^
    = note: partial move occurs because `parent.child` has type `Option<ChildStruct>`, which does not implement the `Copy` trait

As I note in the example code, I can assign Some(child) back to parent.child in order to "put it back", but I'm unsure if this is best practice or has implications for memory. I could also ostensibly implement Copy on the metadata struct but it contains only fields with Vec<u32> and u32 so this is not a great solution for my use case.

What is the most straightforward way to deal with this partial move?

Way Spurr-Chen
  • 405
  • 2
  • 9
  • 1
    `Option::take` or `Option::as_ref` may be useful. Also, if you're just using `Vec` and `u32` cloning is an option. – Aiden4 Jun 09 '21 at 00:49
  • @Aiden4 I did end up finding and using `as_ref`! I just wasn't sure which is "correct" for my use case, but it certainly seems the most convenient for now. – Way Spurr-Chen Jun 09 '21 at 01:43

0 Answers0