问题
Consider this example:
struct Item {
x: u32,
}
impl Item {
pub fn increment(self, amount: u32) -> Self {
Item { x: self.x + amount }
}
}
struct Container {
item: Item,
}
impl Container {
pub fn increment_item(&mut self, amount: u32) {
// This line causes "cannot move out of borrowed content"
self.item = self.item.increment(amount);
}
}
As you can see, Item.increment
consumes the item and returns a new instance.
In Container.increment_item
I want to replace the current item with the one returned by Item.increment
but the compiler yells at me with a cannot move out of borrowed content
error.
In Container.increment_item
self
is mut
so I can mutate its fields, I don't understand why the compiler doesn't allow me to do it.
I know that I can make Container.increment_item
consumes self
and return a new object, like Item.increment
does, and it works, but I would like to understand why I'm getting the error and how can I fix it when I really can't consume the container.
回答1:
Item::increment
expectsself
by value, it moves theItem
on which it is invoked.Container::increment_item
takes&mut self
by reference, it allows you to mutateself
, but it does not allow you to take ownership ofself
(or of any of its parts).- When you invoke
self.item.increment(amount)
, you are trying to passself.item
by value, thus moving ownership to theItem::increment
function, but you are not allowed to do this with references to values that you don't own.
Just pass self
to Item::increment
by mutable reference, that's exactly what mutable references are for:
struct Item {
x: u32,
}
impl Item {
pub fn increment(&mut self, amount: u32) {
self.x += amount;
}
}
struct Container {
item: Item,
}
impl Container {
pub fn increment_item(&mut self, amount: u32) {
self.item.increment(amount);
}
}
If you insist on taking ownership of Item
, then you could use mem::replace
:
use std::mem;
struct Item {
x: u32,
}
impl Item {
pub fn increment(self, amount: u32) -> Self {
Item { x: self.x + amount }
}
}
struct Container {
item: Item,
}
impl Container {
pub fn increment_item(&mut self, amount: u32) {
self.item = mem::replace(&mut self.item, Item { x: 0 }).increment(amount);
}
}
but it seems unnecessarily complicated in this case.
回答2:
increment_item()
takes Container
by reference and item
cannot be moved (or "consumed") while it is behind a reference since increment()
takes Item
by value. Quickest way to fix this is to make Item
a Copy
type. This will trigger a copy and not a move (i.e consume). playground
#[derive(Clone, Copy)]
struct Item {
x: u32,
}
For more, please refer Copy
来源:https://stackoverflow.com/questions/54267665/cannot-move-out-of-borrowed-content-when-replacing-a-struct-field