Error: use of partially moved value: `self`


#1

I have a big method paint, that takes self by value as it is needed by some external functions.
Its signature is like this:

pub fn paint(mut self, renderer: &mut Renderer) -> Win {
    // Some code
    // Some more code
    // And some other code
}

I want to do some refactoring and take second section of code to other method. I do it like this:

pub fn paint(mut self, renderer: &mut Renderer) -> Win {
    // Some code
    self.paint_internal();
    // And some other code
}

fn paint_internal(mut self) {
    // Some more code
}

But compiler is complaining:

error: use of partially moved value: self

How can I circumvent this? Why just extracting of some code to a new method becomes such a struggle?


#2

You’re moving self into paint_internal; you can’t use it afterwards.


#3

To elaborate a bit: using mut self always moves the item, so when you call paint_internal, you’re moving the instance into that method. When that method returns, the moved item goes out of scope, and so gets cleaned up (destroyed). The solution is to do paint_internal(&mut self) instead. I can’t comment on how the “external functions” you reference are configured, but as a general rule you’re better off borrowing references rather than moving the object into a method like this.

Edit: if for some reason you need to use move semantics on that particular method, note that you can always return the reference, with something like this:

pub fn paint(mut self, renderer: &mut Renderer) -> Win {
    // Some code
    self = self.paint_internal();
    // And some other code
}

fn paint_internal(mut self) {
    // do lots of stuff...
    // finish by just returning self
    self
}

That gets a bit hairy, though; in this case you’re almost certainly better just using a reference. Also, the Rust book chapter on References and Borrowing should be helpful in thinking through how to tackle this sort of thing. :slight_smile:


#4

It’s hard to answer exactly without seeing the rest of the code; in cases like this, it can be useful to provide a short, self-contained, correct example of the behavior that you’re seeing to make it easier to talk about a concrete issue. In the Rust world, it can be really helpful to trim your problem down to the minimum that can be used to reproduce it on the Playpen, since that makes it very easy for someone else to run it, fix it, and show you the fixed version.

In general, the error that you’re getting is because you are moving values. Moving a value means that the function passing the value in is giving up ownership of it, to the function that it is calling. After doing so, the function that passed the value in can no longer use it, because the function that it passed it to may have deallocated it, may have done things to invalidate pointers into it, or any number of other things.

The particular error that you are getting says "use of partially moved value: self". This indicates to me that you probably moved out one of the components of self before calling your paint_interval() method. For example, something like this; I’ve removed the parameters and return values that don’t play a part in this example to make it simpler (playpen):

struct Internal;

impl Internal {
    fn manipulate(self) {}
}

struct Paintable {
    a: Internal,
    b: Internal,
}

impl Paintable {
    fn paint(self) {
        self.a.manipulate();
        self.b.manipulate();
    }
}

fn main() {
    let p = Paintable{ a: Internal, b: Internal };
    
    p.paint()
}

Each of those calls to manipulate consumes the object that is part of the self in the paint method, so after the first one, self is considered to be a partially moved value; it no longer has ownership of the first Internal object, so only the second one can still be used, and ownership of the entire Paintable cannot be transferred. For instance, factoring out that second call reproduces your error (playpen):

impl Paintable {
    fn paint(self) {
        self.a.manipulate();
        self.paint_internal()
    }
    
    fn paint_internal(self) {
        self.b.manipulate();
    }
}

How would you solve this problem? There are a few choices. One is to have manipulate take self by reference, rather than by value. Then it doesn’t consume a part of the Paintable, so you can continue to use it later (playpen):

impl Internal {
    fn manipulate(&self) {}
}

Or if Internal is a simple value type, that should just be copied when you pass it into something like manipulate, you could have it implement Copy, so manipulate will just get a copy of it and the original copy will still be valid (playpen):

#[derive(Copy, Clone)]
struct Internal;

Note that if the problem is what I think it is based on the error, the suggestion that @chriskrycho makes about making paint_internal take &mut self won’t work, because the self value is still partially moved, and you can’t pass a reference to a partially moved object into a function. His suggestion would only work if you were getting an error about self being moved in the // And some other code portion that happens after self.paint_internal(), but in that case you would get an error about use of a moved value rather than use of a partially moved value, such as the following (playpen):

fn paint(self) {
    self.paint_internal();
    self.a.manipulate();
}

This subtle difference is why I recommend include a complete, but minimal, example that demonstrates the error, as it’s easy to misdiagnose a problem without full information.


#5

You, guys, are truly awesome!

@lambda, you guessed my problem correctly. I apologize for not so good example of code in the question. My problem was that one of the fields (sdl2::render::Texture) was consumed by sdl2::render::RenderTarget.set() method.

I made this field as Option from the start, and now after this copy() I’m doing self.texture = None. I can do this because later in this paint() method I get that texture back from RenderTarget.reset() method.

Thank you all!


#6

Ah, yes, I should have listed another possibility for solving the problem, which you allude to; making the value in Paintable be Option<Internal>, and then setting it to None after you’ve taken out the value. There is actually a helper on Option, take to do this for you, moving out the value of an Option and setting it to None (playpen):

struct Paintable {
    a: Option<Internal>,
    b: Internal,
}

impl Paintable {
    fn paint(mut self) {
        self.a.take().map(Internal::manipulate);
        self.paint_internal()
    }
    
    fn paint_internal(self) {
        self.b.manipulate();
    }
}

Of course, just doing that yourself is not hard either; just wanted to point out the helper in case it’s convenient.