Hi,
I need to mutate an enum along those lines:
enum Bla {
A(X, Y),
B(X),
}
impl Bla {
fn to_b(&mut self) {
// if A, put X into B, else do nothing.
}
}
What is the best way to do this?
Hi,
I need to mutate an enum along those lines:
enum Bla {
A(X, Y),
B(X),
}
impl Bla {
fn to_b(&mut self) {
// if A, put X into B, else do nothing.
}
}
What is the best way to do this?
This is tricky because the value referenced by self
needs to be valid at all times. For example, if your function to_b
panics at some point in the middle, and the stack is going to be unwound, the value must not be in some invalid intermediate state.
You have several different options.
self
instead of &mut self
:enum Bla<X, Y> {
A(X, Y),
B(X),
}
impl<X, Y> Bla<X, Y> {
fn to_b(self) -> Self {
match self {
Bla::A(a, _) => Bla::B(a),
v => v
}
}
}
enum Bla<X, Y> {
A(X, Y),
B(X),
None
}
impl<X, Y> Bla<X, Y> {
fn to_b(&mut self) {
*self = match std::mem::replace(self, Bla::None) {
Bla::A(a, _) => Bla::B(a),
v => v
}
}
}
enum Bla<X, Y> {
A(X, Y),
B(X),
}
impl<X: Default, Y> Bla<X, Y> {
fn to_b(&mut self) {
*self = match std::mem::replace(self, Bla::B(Default::default())) {
Bla::A(a, _) => Bla::B(a),
v => v
}
}
}
use std::ptr;
enum Bla<X, Y> {
A(X, Y),
B(X),
}
impl<X, Y> Bla<X, Y> {
fn to_b(&mut self) {
unsafe {
ptr::write(self, match ptr::read(self) {
Bla::A(a, _) => Bla::B(a),
v => v
})
}
}
}
I already knew about the first variant. Your other three variants are very instructive! I couldn't get it to work and now I see why. (At first I assumed that this would work with NLL, but it didn't.)
The take_mut
crate provides a safe way to write @jethrogb's 4th implementation.
extern crate take_mut;
impl Bla {
fn to_b(&mut self) {
take_mut::take(self, |bla| match bla {
Bla::A(a, _) => Bla::B(a),
v => v,
})
}
}
Good to know, thanks!