"cannot move out of borrowed content" 替换结构字段时
"cannot move out of borrowed content" when replacing a struct field
考虑这个例子:
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
消耗了该项目并且 return 是一个新实例。
在 Container.increment_item
中,我想用 Item.increment
编辑的 return 替换当前项目,但编译器对我大喊 cannot move out of borrowed content
错误。
在Container.increment_item
中self
是mut
所以我可以改变它的字段,我不明白为什么编译器不允许我这样做。
我知道我可以让 Container.increment_item
消耗 self
和 return 一个新对象,就像 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
无法移动(或 "consumed"),因为它位于引用后面,因为 increment()
获取 Item
按值。解决此问题的最快方法是将 Item
设为 Copy
类型。这将触发复制而不是移动(即消耗)。 playground
#[derive(Clone, Copy)]
struct Item {
x: u32,
}
更多请参考Copy
考虑这个例子:
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
消耗了该项目并且 return 是一个新实例。
在 Container.increment_item
中,我想用 Item.increment
编辑的 return 替换当前项目,但编译器对我大喊 cannot move out of borrowed content
错误。
在Container.increment_item
中self
是mut
所以我可以改变它的字段,我不明白为什么编译器不允许我这样做。
我知道我可以让 Container.increment_item
消耗 self
和 return 一个新对象,就像 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
无法移动(或 "consumed"),因为它位于引用后面,因为 increment()
获取 Item
按值。解决此问题的最快方法是将 Item
设为 Copy
类型。这将触发复制而不是移动(即消耗)。 playground
#[derive(Clone, Copy)]
struct Item {
x: u32,
}
更多请参考Copy