“cannot move out of borrowed content” when replacing a struct field [duplicate]

吃可爱长大的小学妹 提交于 2019-12-13 03:23:26

问题


Consider this example:

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);
    }
}

As you can see, Item.increment consumes the item and returns a new instance.

In Container.increment_item I want to replace the current item with the one returned by Item.increment but the compiler yells at me with a cannot move out of borrowed content error.

In Container.increment_item self is mut so I can mutate its fields, I don't understand why the compiler doesn't allow me to do it.

I know that I can make Container.increment_item consumes self and return a new object, like Item.increment does, and it works, but I would like to understand why I'm getting the error and how can I fix it when I really can't consume the container.


回答1:


  • Item::increment expects self by value, it moves the Item on which it is invoked.
  • Container::increment_item takes &mut self by reference, it allows you to mutate self, but it does not allow you to take ownership of self (or of any of its parts).
  • When you invoke self.item.increment(amount), you are trying to pass self.item by value, thus moving ownership to the Item::increment function, but you are not allowed to do this with references to values that you don't own.

Just pass self to Item::increment by mutable reference, that's exactly what mutable references are for:

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);
    }
}

If you insist on taking ownership of Item, then you could use 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);
    }
}

but it seems unnecessarily complicated in this case.




回答2:


increment_item() takes Container by reference and item cannot be moved (or "consumed") while it is behind a reference since increment() takes Item by value. Quickest way to fix this is to make Item a Copy type. This will trigger a copy and not a move (i.e consume). playground

#[derive(Clone, Copy)]
struct Item {
    x: u32,
}

For more, please refer Copy



来源:https://stackoverflow.com/questions/54267665/cannot-move-out-of-borrowed-content-when-replacing-a-struct-field

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!