How to match the enum and replace it in some branches using some parameters in the new variant?
This is example is not compiling with "cannot move out of `self.state` as enum variant `State0` which is behind a mutable reference". I understand why this code is wrong, but how to achieve the desired result? I tried matching against a reference, but then I just get another compilation error.
struct Foo {}
enum State {
State0(Foo),
State1(Foo),
State2,
}
struct Bar {
state: State,
}
impl Bar {
fn process(&mut self) {
match self.state {
State::State0(foo) => {
println!("state 0");
self.state = State::State1(foo);
}
State::State1(foo) => {
println!("state 1");
},
State::State2 => {
println!("state 2");
}
}
}
}
fn main() {
let mut t = Bar {state: State::State0(Foo{})};
t.process();
t.process();
}
Wow. I'm still not used to such things. So we give ownership to the method and then the method returns it.
Actually, it's still mutating the same instance, but through giving away ownership and not through mutable reference.
If you want to stick to your mutating version, you can do so by matching a reference of self.state and cloning foo from State0 to State1. We have to move foo somehow from one state to the other and that is only possible with ownership (like I showed in my example above), or by creating a new instance of Foo, avoiding moving out of a shared reference. Playground.
Foo is not clonable. It's actually a (tx,rx) of mpsc channels.
One more possibility is to replace self.state with some temporary state. But that makes it hard to return errors from inside the match statement. playground link
use std::mem;
#[derive(Debug)]
struct Foo {}
enum State {
State0(Foo),
State1(Foo),
State2,
}
struct Bar {
state: State,
}
impl Bar {
fn process(&mut self) {
self.state = match mem::replace(&mut self.state, State::State2) {
State::State0(foo) => {
println!("state 0 {:?}", foo);
State::State1(foo)
}
State::State1(foo) => {
// unfortunately it is not possible to use `prev_state @`
// if I want to access foo
println!("state 1 {:?}", foo);
State::State1(foo)
},
prev_state @ State::State2 => {
println!("state 2");
prev_state
}
}
}
}
fn main() {
let mut t = Bar {state: State::State0(Foo{})};
t.process();
t.process();
}
So here is the final version of what I'm going to implement. I really like the idea of ownership transferred to the method and back, but this variant looks cleaner to me. playground