У меня есть структура B
, которая реализует черту Trait
методом do_something
. Мне нужно выполнить некоторые дополнительные действия, когда struct B
отброшена, если эта функция не была вызвана. В частности, если do_something
никогда не вызывался, Vec<A>
должен быть заполнен A::None
:
enum A {
V1,
V2,
None,
}
struct B {
data: Option<(A, Vec<A>)>,
}
trait Trait {
fn do_something(self) -> Vec<A>;
}
impl Trait for B {
fn do_something(mut self) -> Vec<A> {
let (a, mut vec) = self.data.take().unwrap();
vec.push(a);
vec
}
}
impl Drop for B {
fn drop(&mut self) {
match self.data.take() {
Some((a, mut vec)) => vec.push(A::None),
_ => {}
}
}
}
Это имеет некоторые логически ненужные проверки match
. Я хочу избежать их и предложил следующее решение:
struct B {
data: (A, Vec<A>),
}
trait Trait {
fn do_something(self) -> Vec<A>;
}
impl Trait for B {
fn do_something(mut self) -> Vec<A> {
let (a, mut vec) = std::mem::replace(&mut self.data, unsafe {
std::mem::MaybeUninit::<(A, Vec<A>)>::uninit().assume_init()
});
std::mem::forget(self);
vec.push(a);
vec
}
}
impl Drop for B {
fn drop(&mut self) {
self.data.1.push(A::None)
}
}
- Правильно ли мое решение
unsafe
? Содержит ли оно неопределенное поведение? - Можно ли избежать использования либо
unsafe
, либо обтекания B.data
в Option
для достижения вышеуказанного поведения?