HashMap remove by a reference to one of the HashMap's keys

Lately i have come across this pattern while working with a HashMap

let mut a = HashMap::from([("a", "b")]);
let b = a.get("a").unwrap();
a.remove(b);

The compiler does not like this:

let b = a.get("a").unwrap();
        ---------- immutable borrow occurs here
a.remove(b);
^^------^^^
| |
| immutable borrow later used by call
mutable borrow occurs here

Is this just hard for the compiler to get right or is there potential for UB that I am not seeing?

I think you can create dangling references with such an access pattern I.e. in this case, I believe:

let mut map = HashMap::from([("b", "b")]);
let b = map.get("b").unwrap();
map.remove(b);
b; // would be a dangling reference, because the value got moved in previous statement
2 Likes

Even if you're not removing the same value, the hash map could still move other values around when removing.

3 Likes

In theory, this sequence of operations would be sound:

  1. Look up the original reference b=&map.get("a")
  2. Use that reference to identify the slot to be removed
  3. Keep the slot id, but drop all live references into the map
  4. Take a mutable reference to the map, and remove the item at the identified slot

Unfortunately, this would require unsafe and access to the internals of HashMap's implementation. You'd also need to guard against the map changing between (3) and (4): During that period, Rust's lifetime rules won't be able to protect you.

1 Like

Note that the original code is easy to fix. The problem is that b is a &'borrow_of_the_hashmap &'static str, but there is no reason you need one of those; you can dereference to get an &'static str.

let mut a = HashMap::from([("a", "b")]);
let b = *a.get("a").unwrap();
a.remove(b);

This works because &'static str: Copy; if your HashMap had a non-Copy type then you would need to .clone() the key so that you have a key whose life is independent of the map.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.