2

I would like to remove a (key, value) from an ordered hashmap depending on some property regarding the value.

I wrote the following minimal example:

use std::collections::BTreeMap;

pub fn remove_if42(map: &mut BTreeMap<String, u32>) -> Option<u32> {
    // Get the first element (minimum) from the ordered hash
    let (key, value) = map.iter_mut().next()?;

    if *value == 42 {
        map.remove(key);
    }
    Some(*value)
}

I can read the value, but when I ask to delete the key, I get a borrowing error:

error[E0499]: cannot borrow `*map` as mutable more than once at a time
 --> src/lib.rs:8:9
  |
5 |     let (key, value) = map.iter_mut().next()?;
  |                        --- first mutable borrow occurs here
...
8 |         map.remove(key);
  |         ^^^        --- first borrow later used here
  |         |
  |         second mutable borrow occurs here
Jeremy Cochoy
  • 2,480
  • 2
  • 24
  • 39
  • `next_back()` doesn't return the first element but the last one. – Stargateur Apr 14 '19 at 18:07
  • 2
    @Shepmaster Deer Shepmaster, you mentionnet this is a duplicate of the question 32913368 (removing-items-from-a-btreemap-or-btreeset-found-through-iteration). Indeed, the two question are différent. This one is related to the borrow checker which still hold a reference to the key, whereas no iterator is involved. In the question you linked, iterator are involved and invalidated. Also, the answer is different. The "possible duplication" answer "No you can't do it". This question have as answer "Yes, duplicate the key". Regards, – Jeremy Cochoy Apr 30 '19 at 15:27

1 Answers1

1

The error is caused by the fact the key and the value are borrowed. The answer is to make a copy of them before calling remove():

use std::collections::BTreeMap;

pub fn remove_if42(map: &mut BTreeMap<String, u32>) -> Option<u32> {
    // Get the first element from the ordered hash
    let (key, value) = map.iter_mut().next_back()?;

    let key_cpy: String = key.to_string();
    let value_cpy = *value;
    if *value == 42 {
        map.remove(&key_cpy);
    }
    Some(value_cpy)
}

In the case you don't need the value after removing the entry, you only need a copy of the key.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Jeremy Cochoy
  • 2,480
  • 2
  • 24
  • 39