Как я могу сделать вычисляемые переходы состояний, не оскорбляя средство проверки заимствования?
Я написал этот код для перехода между состояниями, но если не удается пройти проверку заимствования:
struct State {
// ...
}
impl State {
fn next(self) -> (Self, u32) {
// ...
}
}
struct StateHolder {
state: State
}
impl StateHolder {
fn next_value(&mut self) -> u32 {
// ERROR: Cannot move out of borrowed context
let (new_state, byproduct) = self.state.next();
self.state = new_state;
return byproduct;
}
}
Это похоже на ситуацию, в которой я обычно использую std::mem::replace
, но поскольку значение new_state
зависит от старого состояния, оно просто не будет работать здесь.
Я знаю, что могу сделать эту работу, сделав State
реализацию Clone
и сделав это:
fn next_value(&mut self) -> u32 {
let (new_state, byproduct) = self.state.clone().next();
self.state = new_state;
return byproduct;
}
Но я бы не хотел делать ненужную копию, как это, или требовать State
, чтобы реализовать Clone
. (Я думаю, что компилятор будет оптимизируйте копию в этом случае, но я не хочу полагаться на это.)
Я также знаю довольно много способов сделать это в небезопасной ржавчине,но это кажется чрезмерным для такой простой и очевидно безопасной модели.
Есть ли способ сделать это в безопасной ржавчине, без ненужного копирования?
1 ответ:
Самый простой способ:
Я буду честен и скажу, что это действительно странно-потреблять и возвращатьfn next(&mut self) -> u32;
self
, и это также непрактично, как показано здесь.
Если вы застряли с
fn next(self) -> (Self, u32)
, но готовы изменить расположениеStateHolder
, идите сstate: Option<State>
, потому чтоOption
имеетtake
:let (new_state, byproduct) = self.state.take().unwrap().next(); self.state = Some(new_state); byproduct
Если вы застряли без
Option
, или это слишком болезненно для использования, то вы действительно можете использоватьstd::mem::replace
, но вам понадобится некотороеState
, чтобы сделать это. Это легко, еслиState
реализуетDefault
, но может стоить дорого:Наконец, вы действительно можете разбитьlet (new_state, byproduct) = std::mem::replace(&mut self.state, State::default()).next(); std::mem::replace(&mut self.state, new_state); byproduct
unsafe
, чтобы переместить значение изself.state
... однако если вычисление когда-нибудь запаникует, прежде чем вы сможете заполнить его обратно, то вы открыли дверь в страну неопределенного поведения, и это baaad.