Example code:
struct S1 {}
struct S2 {}
struct S3 {}
enum State {
Zero,
One(S1),
Two(S1, S2),
Three(S1, S2, S3),
}
struct Client {
state: Option<State>,
}
impl Client {
fn try_advancing(&mut self) {
/* other code */
if let Some(inner) = std::mem::replace(&mut self.state, None) {
match inner {
State::Zero => {
if predicate0() {
self.state = Some(State::One(S1 {}));
}
else {
// code won't compile as we
// no longer own inner after partial move
self.state = Some(inner);
}
},
State::One(s1) => {
if predicate1() {
self.state = Some(State::Two(s1, S2 {}));
}
else {
self.state = Some(inner);
}
},
State::Two(s1, s2) => {
if predicate2() {
self.state = Some(State::Three(s1, s2, S3 {}));
}
else {
self.state = Some(inner);
}
},
State::Three(..) => {
if predicate3() {
// something else happens now
}
}
}
}
}
}
I need to look at state to determine whether to move to the next transition, but if I borrow it, then I can't transition because I don't own the value.
As possible solutions, I could use
smart pointers
a second match statement (the first borrowing and determine if we need to transition, the second moving and doing the transition)
"rebuilding" the enum as it was, i.e.
self.state = Some(inner);becomesself.state = State::Zero;only borrow the contents of inner until I know I want to transfer ownership, then do an if let, e.g.
State::One(ref s1) => {
if predicate1() {
if let State::One(s1) = inner {
self.state = Some(State::Two(s1, S2 {}));
- Derive
CopyandClonefor the unit structs.
All of those solutions incur run-time costs and what I would consider inelegant code. If this were another language, I could write the algorithm the way I think it should be, but with Rust, lifetimes seem to be preventing me from doing so. If only there were a way to tell the Rust compiler "in this branch of the if statement, I want to rescind my partial move and move inner back to where it was." Or perhaps, "Yes, I was borrowing the data, but now I no longer need those references and want to move the data." Is there such a way? Or any better alternative I haven't considered?