考虑这个例子:
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
所以我可以改变它的字段,我不明白为什么编译器不允许我这样做。
我知道我可以像Item.increment
一样使Container.increment_item
消耗self
并返回一个新对象,并且它可以工作,但我想了解为什么我会收到错误以及当我真的无法使用容器时如何修复它。
-
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);
}
}
但在这种情况下,这似乎不必要地复杂。
increment_item()
通过引用获取Container
,并且item
在引用后面时无法移动(或"消耗"),因为increment()
按值获取Item
。解决此问题的最快方法是使Item
成为Copy
类型。这将触发复制而不是移动(即消耗)。操场
#[derive(Clone, Copy)]
struct Item {
x: u32,
}
欲了解更多信息,请参阅复制