type Foo(u32);
impl Foo {
fn some_mutation(self) -> Self {
// pretend this is a more complicated mutation that can't be
// rewritten to take &mut self (and may possibly panic)
Foo(self.0 + 1)
}
fn mutate_in_place(&mut self) {
// Is there some way I can call self.some_mutation() here
// and store the result back in self?
// I'd be okay with using unsafe code here (i.e. cast the
// reference to a pointer and manually call read() and write()).
// Is it sound to do that, and if so, is there a helper function
// that does it so I don't have to?
}
}
You can move out of a &mut
as long as you promise to immediately replace it with valid data (it's ok if its only purpose in life is to be a temporary placeholder), then put it back later and throw away the temporary placeholder data. For example, you can put some Default::default()
data in there using std::mem::take()
, or if you don't implement Default
for whatever reason, you can construct a throwaway value of your own and use std::mem::replace()
instead. If your type is Copy
then you can operate on a temporary copy and write the result afterwards.
The exact thing you are looking for does not exist AFAIK (basically a fn replace_with<T, F: FnOnce(T) -> T>(dest: &mut T, f: F)
)
It does exist:
There are various flavors, all with caveats. The property that has to be guaranteed is that on function return or unwind due to panic, there will always be a valid Foo
behind the &mut Foo
. (One way to ensure this is "abort instead of unwinding".)
Not without taking other steps to ensure an unitialized value is never observable. "Other steps" could be replacing with a default value, using Option<_>
instead, or some careful use of unsafe
and other measures (such as aborting on panic) to move the value out from underneath the &mut _
. See this article.
The article mentions the take_mut
crate; a more recent crate to handle this scenario is replace_with
. It encapsulates the unsafe
for the approaches that require it.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.