Replacing values in Rust causing “cannot move out

2019-08-26 20:53发布

This question already has an answer here:

I'm trying to build a graphics engine that works with the fairly common two-buffer pattern. One buffer (current_buffer) is displayed while the next (next_buffer) is prepared, then the next buffer is moved into the current buffer, and is subsequently repopulated by a new buffer, repeating.

I know there are a lot of other questions about cannot move out of borrowed content errors, so I spent a while looking at all I can find so far before finally resorting to asking this as a question.

Here's my code:

pub fn update(&mut self, dt: f64) {
    if self.is_change_buffer {
        self.current_buffer = self.next_buffer;
        self.next_buffer = Buffer { ... }; // New buffer
    }
}

I'm running into problems with moving self.next_buffer to self.current_buffer, which is understandable considering that self.current_buffer = self.next_buffer would break the "one owner" principle. How do I tell the borrow checker that I'm not trying to alias self.next_buffer, I'm trying to move it, and put something new in its place?

A caveat due to a framework I'm working with is that the function signature of update() must be:

pub fn (&mut self, dt: f64) -> ()

Also, a Buffer cannot be cloned. Because of the way Buffers are stored, cloning them would be an extremely expensive operation, and so cannot practically be done at every screen refresh.

2条回答
趁早两清
2楼-- · 2019-08-26 21:33

Probably the easiest solution is to use std::mem::swap:

std::mem::swap(&mut self.next_buffer, &mut self.current_buffer);
self.next_buffer = Buffer { ... }; // New buffer

You can also assign first and then swap, but I find it more natural this way.

查看更多
霸刀☆藐视天下
3楼-- · 2019-08-26 21:42

How do I tell the borrow checker that I'm not trying to alias self.next_buffer, I'm trying to move it, and put something new in its place?

The borrow checker is not complaining about aliasing – it is complaining because you are moving a field out of a struct that you only borrowed, which is not allowed. However, moving out and immediately replacing with a new value is allowed, and there is a dedicated function for exactly this use case, called std::mem::replace(). With this function, your code becomes

self.current_buffer = mem::replace(&mut self.next_buffer, Buffer { ... });
查看更多
登录 后发表回答