Using a method that takes self from a method that takes &mut self

Given

struct TakesSelf;
impl TakesSelf {
    fn take(self) -> Self { ... }
}

and we would like to use it like this

struct UsesSelf(TakesSelf);
impl UsesSelf {
    fn use(&mut self) {
        self.0 = self.0.take();
    }
}

We get this function takes ownership of the receiver self, which moves self.0. Okay I understand that for a brief moment, UsesSelf::use is in an inconsistent state when it calls take() and consumes it's struct member. Leaving the member undefined. But.. use(&mut self) is a unique reference. Meaning nowhere else in code is this data being used at that moment? Right? And we do eventually make UsesSelf whole again by assigning to it a new property value before returning and releasing the &mut self unique reference.

Do I have to do some kind of mem swap?

The problem is that if take panics, then the field remains undefined. One option is to use mem::replace to put a dummy value in the meantime.

The other option is to use the take_mut crate, which lets you do what you want. However, it aborts the program if the method panics. (Or you could use its take_or_recover method to construct a dummy value on panic.)

2 Likes

Thank you, take_mut does exactly what I want. Though a bit awkward with the anonymous function. I almost never allow recovering from a panic. So if that was to happen, I'd prefer to hint to the compiler that the program terminates here, incomplete state or not.

Here's an article on the topic more generally.

replace_with is an alternative to take_mut with a bit more control.

1 Like