Mutable/immutable borrow conflict for "scan for a key to remove from a map" pattern - how to resolve?

⚓ Rust    📅 2026-05-03    👤 surdeus    👁️ 3      

surdeus

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))
}

(Playground)

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

1 post - 1 participant

Read full topic

🏷️ Rust_feed