I would like to extract a value from a pattern matched mutable reference and discard the old one.
This is a minimal example I've come up with:
fn main() {
#[derive(Debug)]
enum D<A> {
E1(A),
E2(A, A),
};
trait Zero<A> {
fn zero() -> A;
}
impl<A> D<A> {
pub fn push2(&mut self, e: A) {
match self {
D::E1(e1) => {
*self = D::E2(*e1, e);
}
_ => unimplemented!(),
}
}
pub fn push(&mut self, e: A)
where
A: Zero<A>,
{
match self {
D::E1(e1) => {
let mut r = A::zero();
std::mem::swap(&mut r, e1);
*self = D::E2(e, r);
}
_ => unimplemented!(),
};
}
}
impl Zero<i32> for i32 {
fn zero() -> i32 {
0
}
}
let mut d = D::E1(10);
d.push(11);
println!("{:?}", d);
}
push2
fails with:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:17:39
|
17 | *self = D::E2(*e1, e);
| ^^^ cannot move out of borrowed content
I would like to achieve this without requiring the Copy
trait as I have some boxed types inside and ideally would like to remove the need for the dummy variable (A::zero()
).
If I understand your code, A
will be some number because it implements Zero
. The numeric values implement Copy
in Rust, so you can use this to your advantage:
pub fn push(&mut self, e: A)
where
A: Zero<A> + Copy,
{
match self {
D::E1(e1) => *self = D::E2(e, *e1),
_ => unimplemented!(),
};
}
If you do not want to bound against Copy
, you can use std::mem::replace
as suggested:
pub fn push(&mut self, e: A)
where
A: Zero<A>,
{
use std::mem::replace;
match self {
D::E1(e1) => *self = D::E2(e, replace(e1, A::zero())),
_ => unimplemented!(),
};
}
That is the idiomatic way to do so.
You need the dummy element because you cannot do this:
D::E1(e1) => *self = D::E2(e, *e1),
The reason is that the compiler evaluates the parameters first, and *e1
tries to take the ownership of borrowed data, but that is forbidden.