Is it possible to switch variants in the value of a mutable reference (&mut E<T>
) without additional constraints on T
, and without resorting to unsafe code?
That is, given an enum:
enum E<T> {
VariantA(T),
VariantB(T)
}
What is the correct way of writing this:
let x: E<???> = E::VariantA(??);
change_to_variant_b(&mut x);
assert_eq!(x, E::VariantB(??));
As an alternative for this particular case, you could consider changing to a struct with a T
and a plain enum:
struct Outer<T> {
val: T,
kind: Inner,
}
impl<T> Outer<T> {
fn promote_to_b(&mut self) {
self.kind.promote_to_b()
}
}
enum Inner {
VariantA,
VariantB,
}
impl Inner {
fn promote_to_b(&mut self) {
if let Inner::VariantA = *self {
*self = Inner::VariantB;
}
}
}
I am going to go on a limb here and say No.
It is possible with just a minor change to the signature though:
fn change_to_variant_b<T>(e: E<T>) -> E<T> {
match e {
E::VariantA(t) => E::VariantB(t),
E::VariantB(t) => E::VariantB(t),
}
}
It is possible using unsafe
:
fn change_to_variant_b<T>(e: &mut E<T>) {
use std::ptr;
unsafe {
match ptr::read(e as *const _) {
E::VariantA(t) => ptr::write(e as *mut _, E::VariantB(t)),
E::VariantB(t) => ptr::write(e as *mut _, E::VariantB(t)),
}
}
}
It is possible with additional bounds (Default
, or Clone
):
fn change_to_variant_b<T: Default>(e: &mut E<T>) {
match std::mem::replace(e, E::VariantA(T::default())) {
E::VariantA(t) => e = E::VariantB(t),
E::VariantB(t) => e = E::VariantB(t),
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With