Единственная используемая вами функция unsafe
- mem::uninitialized
.Вам нужно что-то передать на mem::replace
, но реализация Default
не сработает, потому что default()
возвращает Self
, что не дает возможности быть объектно-безопасным.Аналогично, вы не можете реализовать Clone
для дублирования старого значения, так как clone()
также возвращает Self
.
Вы можете просто реализовать фиктивный тип для этой цели:
struct Dummy;
impl T for Dummy {}
fn wrap_t(&mut self) {
let old_t = mem::replace(&mut self.t, Box::new(Dummy));
let new_t = Box::new(Self::new(old_t));
mem::replace(&mut self.t, new_t);
}
Вам также не понадобится mem::forget
здесь и сейчас (я предполагаю, что он был там для предотвращения неопределенного поведения, когда неинициализированная память была отброшена).
Как альтернатива Clone
, вы можете бросить свой собственный, который клонирует к Box<dyn T>
, избегая наличия Self
в сигнатуре метода, поэтому черта сохраняет объект в безопасности:
trait T: Debug {
fn clone_in_box(&self) -> Box<dyn T>;
}
impl T for S {
fn clone_in_box(&self) -> Box<dyn T> {
Box::new(S {
t: self.t.clone_in_box(),
})
}
}
fn wrap_t(&mut self) {
let cloned = self.clone_in_box();
let old_t = mem::replace(&mut self.t, cloned);
let new_t = Box::new(Self::new(old_t));
mem::replace(&mut self.t, new_t);
}
Существует также альтернативный дизайн, который намного проще понять при чтении кода.Это просто для использования self
и возврата нового объекта:
fn wrap_t(self) -> Self {
Self::new(Box::new(Self::new(self.t)))
}
И вместо этого:
s.wrap_t();
Вы бы сделали:
s = s.wrap_t();