替换结构字段时"cannot move out of borrowed content"



考虑这个例子:

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,
}

欲了解更多信息,请参阅复制

相关内容

最新更新