这个问题在这里已有答案:
考虑这个例子:
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
一样,并且它可以工作,但我想知道为什么我得到错误,我怎么能解决它,当我真的不能消耗容器。
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
类型。这将触发副本而不是移动(即消耗)。 playground
#[derive(Clone, Copy)]
struct Item {
x: u32,
}
有关更多信息,请参阅Copy