Consider the following code:
enum Deferred<F, T> {
Fn(F),
Ready(T),
}
impl<F, T> Deferred<F, T>
where
F: FnOnce() -> T,
T: Clone,
{
fn get_clone(&mut self) -> T {
let clone;
*self = match *self {
Self::Fn(f) => { // `f` moved here
let data = f(); // this needs to consume `f`
clone = data.clone();
Self::Ready(data)
},
Self::Ready(data) => { // `data` moved here
clone = data.clone();
Self::Ready(data)
},
};
clone
}
}
The compiler complains about the *self = match *self {...};
statement because its right hand side takes ownership of contents of self
. Is there a way to accomplish this behaviour with just a mutable reference to self
?
I found a workaround using F: FnMut() -> T
so that f
doesn't have to be moved but this approach clearly has its limitations.
I also tried what the answer to Is there a safe way to temporarily retrieve an owned value from a mutable reference in Rust? suggested but it led to an issue with initialization of clone
(the compiler could no longer reason that the match statement would initialize clone
because the code was moved into a closure) so I had to use MaybeUninit
with unsafe
.
At that point it was better to read/write self
through a raw pointer:
unsafe {
std::ptr::write(
self as *mut Self,
match std::ptr::read(self as *const Self) {
Self::Fn(f) => {
let data = f();
clone = data.clone();
Self::Ready(data)
},
Self::Ready(data) {
clone = data.clone();
Self::Ready(data)
},
}
);
}