How do I move out of a struct field that is an Opt

2019-02-22 07:20发布

I want to collect changes to a struct and apply them all at once. The basic outline looks like this:

enum SomeEnum {
    Foo,
    Bar,
}

struct SomeStruct {
    attrib: SomeEnum,
    next_attrib: Option<SomeEnum>,
}

impl SomeStruct {
    pub fn apply_changes(&mut self) {
        if let Some(se) = self.next_attrib {
            self.attrib = se;
        }
        self.next_attrib = None;
    }
}

which yields the following compiler error:

error[E0507]: cannot move out of borrowed content
  --> src/lib.rs:13:27
   |
13 |         if let Some(se) = self.next_attrib {
   |                     --    ^^^^ cannot move out of borrowed content
   |                     |
   |                     hint: to prevent move, use `ref se` or `ref mut se`

I found Get an enum field from a struct: cannot move out of borrowed content and added #[derive(Clone, Copy)] to my enum's definition.

This may work but I feel uncomfortable about (implicitly) using copying since this could generally happen to larger datatypes as well.

The actual owner is never moved out of the struct.

Is there another way to accomplish this, without exposing the Copy/Clone traits to all users of the enum?

1条回答
祖国的老花朵
2楼-- · 2019-02-22 08:05

It's unclear how well you follow the overall issue, but essentially, you can't assign the value to self.attrib if it's still owned by self.next_atrrib. That means you need so remove the value from self.next_attrib and then give ownership to self.attrib.

One way to do this would be to manually replace the value. For instance, you could use std::mem::replace:

impl SomeStruct {
    pub fn apply_changes(&mut self) {
        let next_attrib = std::mem::replace(&mut self.next_attrib, None);
        if let Some(se) = next_attrib {
            self.attrib = se;
        }
    }
}

to replace the value with None and take ownership of the current value as next_attrib. Then you can take the value and, if it is Some(_), you can place its content in self.attrib.

Since this is a relatively common pattern, however, there is a utility function on Option to handle situations where you'd like to take ownership of the contents of an Option and set the Option to None. The Option::take method is what you want.

impl SomeStruct {
    pub fn apply_changes(&mut self) {
        if let Some(se) = self.next_attrib.take() {
            self.attrib = se;
        }
    }
}
查看更多
登录 后发表回答