The code below won't compile. The problem is straightforward: a call to BTreeMap::remove requires an &mut reference to the map, but max_key holds an immutable reference to one of the map's keys, rendering the map immutable for the duration of that reference.
But I don't see any good way to fix it, because the key is, in my actual code, not Copy (it is Clone, but a clone is quite expensive). And extract_if can't be used because we don't know which element to remove until we've scanned the entire map. So I'm stuck. Any ideas?
use std::collections::BTreeMap;
pub fn pop_max_weight<K: Ord, V, F: Fn(&V) -> usize>(
map: &mut BTreeMap<K, V>,
weight: F
) -> Option<V> {
let mut max_weight = 0usize;
let mut max_key = None;
for (k, v) in map.iter() {
let k_weight = weight(v);
if k_weight > max_weight {
max_weight = k_weight;
max_key = Some(k);
}
}
max_key.and_then(|k| map.remove(k))
}
Errors:
Compiling playground v0.0.1 (/playground)
error[E0500]: closure requires unique access to `*map` but it is already borrowed
--> src/lib.rs:16:22
|
9 | for (k, v) in map.iter() {
| --- borrow occurs here
...
16 | max_key.and_then(|k| map.remove(k))
| -------- ^^^ --- second borrow occurs due to use of `*map` in closure
| | |
| | closure construction occurs here
| first borrow later used by call
For more information about this error, try `rustc --explain E0500`.
error: could not compile `playground` (lib) due to 1 previous error
(P.S. I know about BinaryHeap, but in my actual code, the weight function depends on external data that's different every time pop_max_weight is called, so that's no good either.)