Как мне выйти из поля структуры, которое является опцией?


Я хочу собрать изменения в структуру и применить их все сразу. Основная схема выглядит следующим образом:

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;
    }
}

, что приводит к следующей ошибке компилятора:

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`

Я нашел получить поле перечисления из структуры: не может выйти из заимствованного содержания и добавил #[derive(Clone, Copy)] к определению моего перечисления.

Это может сработать, но мне неудобно (неявно) использовать копирование, поскольку это обычно может произойти и с большими типами данных.

В фактический владелец никогда не выходит из структуры.

Есть ли другой способ выполнить это, не подвергая опасности Copy/Clone черты для всех пользователей перечисления?

1 5

1 ответ:

Неясно, насколько хорошо вы следуете общей проблеме, но, по сути, вы не можете присвоить значение self.attrib, если оно все еще принадлежит self.next_atrrib. Это означает, что вам нужно удалить значение из self.next_attrib, а затем передать право собственности self.attrib.

Один из способов сделать это-вручную заменить значение. Например, вы могли бы использовать 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;
        }
    }
}

Заменить значение на None и принять во владение текущее значение как next_attrib. Тогда вы можете взять значение и, если оно равно Some(_), вы можете поместить его содержимое в self.attrib.

Поскольку это относительно распространенный шаблон, однако, есть функция полезности на Option для обработки ситуаций, когда вы хотели бы взять на себя ответственность за содержимое Option и установить Option в None. Тот самый Option::take метод - это то, что вам нужно.

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