1
votes

I have a Element struct that implements an update method which takes a tick duration. The struct contains a vector of components. These components are allowed to modify the element on an update. I'm getting a borrow error here and I'm not sure what to do. I tried fixing it with a block, but the block doesn't seems to satisfy the borrow checker.

use std::collections::HashMap;
use std::time::Duration;

pub struct Element {
    pub id: String,
    components: HashMap<String, Box<Component>>,
}

pub trait Component {
    fn name(&self) -> String;
    fn update(&mut self, &mut Element, Duration) {}
}

impl Element {
    pub fn update(&mut self, tick: Duration) {
        let keys = {
            (&mut self.components).keys().clone()
        };
        for key in keys {
            let mut component = self.components.remove(key).unwrap();
            component.update(self, Duration::from_millis(0));
        }
    }
}

fn main() {}

The Error

error[E0499]: cannot borrow `self.components` as mutable more than once at a time
  --> src/main.rs:20:33
   |
17 |             (&mut self.components).keys().clone()
   |                   --------------- first mutable borrow occurs here
...
20 |             let mut component = self.components.remove(key).unwrap();
   |                                 ^^^^^^^^^^^^^^^ second mutable borrow occurs here
...
23 |     }
   |     - first borrow ends here

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/main.rs:21:30
   |
17 |             (&mut self.components).keys().clone()
   |                   --------------- first mutable borrow occurs here
...
21 |             component.update(self, Duration::from_millis(0));
   |                              ^^^^ second mutable borrow occurs here
22 |         }
23 |     }
   |     - first borrow ends here
1

1 Answers

4
votes

The keys() method returns an iterator over the keys in the hashmap. The clone() call only duplicates the iterator, but not the keys themselves. Your original approach with the map function looks promising. You probably need to collect the result in a Vec using the collect() method of the iterator:

let keys = self.components.keys().cloned().collect::<Vec<_>>();

And then:

for key in keys {
    self.components.remove(&key).unwrap();
}

This ensures that all the keys are copied before the removal operation starts.