0

I have an error in Rust where I'm iterating (iter_mut()) items in a list that is a part of self. With each item, I'm calling a function on the item and passing self in.

I believe the problem is essentially that I'm borrowing self twice, once when I access the Vec to iterate it, and then another time when I pass it in.

I tried to minimize my code as small as possible to get the same error. Don't think too hard about why I'm passing self in just to access increment_val - it makes more sense in the real code.

struct VecItem {
    val: usize,
}

impl VecItem {
    fn increment(&mut self, incr: &ItemIncrementer) {
        self.val += incr.increment_val;
    }
}

struct ItemIncrementer {
    items: Vec<VecItem>,
    pub increment_val: usize,
}

impl ItemIncrementer {
    fn new() -> Self {
        let mut res = Self {
            items: Vec::new(),
            increment_val: 5,
        };
        res.items.push(VecItem { val: 1 });
        res.items.push(VecItem { val: 2 });
        res.items.push(VecItem { val: 3 });
        res
    }
    fn increment_all(&mut self) {
        for item in self.items.iter_mut() {
            item.increment(self);
        }
    }
}

fn main() {
    let mut incr = ItemIncrementer::new();
    incr.increment_all();
}

The error I'm getting is

cargo run
   Compiling hashmap_test v0.1.0 (/home/creedthoughts/hashmap_test)
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
  --> src/main.rs:29:28
   |
28 |         for item in self.items.iter_mut() {
   |                     ---------------------
   |                     |
   |                     mutable borrow occurs here
   |                     mutable borrow later used here
29 |             item.increment(self);
   |                            ^^^^ immutable borrow occurs here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0502`.
error: could not compile `hashmap_test`.

To learn more, run the command again with --verbose.

In other questions similar to this, it seems the general solution is to separate the first borrow into a separate scope from the other borrow. I have no idea how to do this though.

d0c_s4vage
  • 3,947
  • 6
  • 23
  • 32
  • 1
    https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8b52069717f3b00c8ebafde14aedd87e example of possible fix – Stargateur May 17 '20 at 00:06
  • @Stargateur that would make sense, but in my real code I need the item to call functions on `self` in order to fetch/build some values. I don't know what those required values are supposed to be ahead of time, or if the item even needs them. – d0c_s4vage May 17 '20 at 00:13
  • @Stargateur the link to the other question seems similar, I'll see if it helps – d0c_s4vage May 17 '20 at 00:14
  • The other question definitely helped! I'll answer my own question – d0c_s4vage May 17 '20 at 14:09

0 Answers0