I'm writing a function that works with a HashMap
and at various points in the function I want to check if any of the values in the map meet a condition and if any does return the key for just one of the entries that meets the condition.
So far, I tried to first iterate over references to check my condition, and then use remove_entry
to get an owned copy of the key rather than a borrow:
use std::{collections::HashMap, hash::Hash};
fn remove_first_odd<K: Hash + Eq>(map: &mut HashMap<K, u64>) -> Option<K> {
let maybe_entry = map.iter().find(|(_, &value)| value & 1 == 1);
match maybe_entry {
Some((key_ref, _value_ref)) => {
let (key_owned, _value_owned) = map.remove_entry(key_ref).unwrap();
Some(key_owned)
}
None => None,
}
}
but this fails borrow checking, because I can't mutate the map while I am still holding a reference to one of the keys in it:
error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
--> src/lib.rs:8:45
|
4 | let maybe_entry = map.iter().find(|(_, &value)| value & 1 == 1);
| --- immutable borrow occurs here
...
8 | let (key_owned, _value_owned) = map.remove_entry(key_ref).unwrap();
| ^^^^------------^^^^^^^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
I believe that this is possible, because as long as remove_entry
only dereferences my key before mutation and not after, this should be sound.
So is there a safe API to do this? If not, can one be created?
Note that:
- I can't clone my keys because they are generic without a clone bound
- I can't consume the
HashMap
with something like.into_iter()
- I only need to remove a single entry, not all of the entries that match