考虑以下示例:
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);
}
}
如您所见,Item.increment
使用该项目并返回一个新实例。
在Container.increment_item
中,我想用Item.increment
返回的内容替换当前项目,但编译器对我大喊cannot move out of borrowed content
。
在Container.increment_item
中,self
是mut
,因此我可以更改其字段,但我不明白为什么编译器不允许我这样做。
我知道我可以使Container.increment_item
消耗self
并返回一个新对象,就像Item.increment
一样,并且它可以工作,但是我想理解为什么我得到了错误以及当我真的无法使用容器时如何解决。
答案 0 :(得分:1)
Item::increment
按值期望self
,它将移动对其进行调用的Item
。Container::increment_item
作为参考引用了&mut self
,它允许您突变self
,但不允许您拥有self
(或其任何部分的所有权) )。self.item.increment(amount)
时,您试图通过值传递self.item
,从而将所有权移至Item::increment
函数,但是不允许通过引用值来实现此目的你不拥有。只需通过可变引用将self
传递到Item::increment
,这正是可变引用的用途:
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);
}
}
如果您坚持拥有Item
的所有权,则可以使用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);
}
}
,但在这种情况下似乎不必要地复杂。
答案 1 :(得分:-1)
increment_item()
被引用Container
,并且item
在引用后面时无法移动(或“消耗”),因为increment()
被引用Item
值。解决此问题的最快方法是将Item
设置为Copy
类型。这将触发副本而不是移动(即消耗)。 playground
#[derive(Clone, Copy)]
struct Item {
x: u32,
}
有关更多信息,请参阅Copy