Phthalo Johnson
Phthalo Johnson

Reputation: 11

How to get access to the keys of a hash map as an iterator while also having a mutable reference to the hash map in Rust?

I have this, which works:

   let clients: &mut HashMap<usize, _some_none_clonable_type> = &mut self.clients;
   let keys = {
      let mut keys = Vec::<usize>::new();
      for key in clients.keys(){
         keys.push(*key);
      }
      keys
   };
   if let Some(client) = clients.get_mut(&id) {
      println!("INFO: The !users macro was sent from user: {id}.");
      client.write_all(format!("User ID's:\n").as_bytes())?;
      for user_id in keys {
         client.write_all(format!("{user_id}\n").as_bytes())?;
      }
   }

But what I actually want is this:

   // first mutable borrow of hashmap
   if let Some(client) = self.clients.get_mut(&id) {
      println!("INFO: The !users macro was sent from user: {id}.");
      client.write_all(format!("User ID's:\n").as_bytes())?;
      // immutable borrow of the same map in the same scope:
      for user_id in self.clients.keys() {
         client.write_all(format!("{user_id}\n").as_bytes())?;
      }
   }

Correct me if I'm wrong but since we don't mutate the keys and we never remove anything, this code should be valid, just not well typed. Of course the compiler complains. Is there a way to circumvent the type checker by using indirections or unsafe? I realize that it's not necessary because I could just check if the entry exists in the hash map and only then borrow, but I'm actually more interested in this type of scenario in general.

Upvotes: 1

Views: 43

Answers (1)

user1280483
user1280483

Reputation: 560

When you call self.clients.get_mut(&id), you call HashMap::get_mut. This takes an &mut self, which means that the borrow checker assumes that the function will return a value that could mutate any part of the HashMap. For example, the value it returns (client) could, upon calling its write_all method, delete the keys of the HashMap while you were iterating over it. The borrow checker doesn't know any better; it's just looking at the function signatures.

At its core, the problem is that you need to mutably borrow the values of a HashMap while immutably borrowing its keys. The HashMap methods don't allow you to do this because it adds complexity, but you could easily test it out yourself with two Vecs, one that holds the keys and one that holds the corresponding values. Of course this makes it a lot harder to work with it, since you now need to handle the keys and values separately. HashMap gives you a simpler interface at the cost of making some operations much harder.

Upvotes: 0

Related Questions