替换结构字段时“无法移出借用的内容”

时间:2019-01-19 13:36:54

标签: rust borrow-checker

考虑以下示例:

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中,selfmut,因此我可以更改其字段,但我不明白为什么编译器不允许我这样做。

我知道我可以使Container.increment_item消耗self并返回一个新对象,就像Item.increment一样,并且它可以工作,但是我想理解为什么我得到了错误以及当我真的无法使用容器时如何解决。

2 个答案:

答案 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