How to end a borrow in a match or if let expression?

I am using a HashMap to store an enum. I'd like to get a value from the HashMap and if the value is a specific enum variant, I'd like to insert a modified copy of the value back in the HashMap.

The code I came up with looks like this:

if let Node::LeafNode(mut leaf_node) = *(self.pages.get(&page).unwrap()) {
   let mut leaf_node = leaf_node.clone();
   // ...
   self.pages.insert(leaf_page,Node::LeafNode(leaf_node)); 
}

This does not compile because the borrow of self.pages lasts until the end of the if let-block and self.pages.insert is a mutable borrow.

I have tried to shadow the value of the HashMap with a copy of the value, but this does not end the borrow. Usually I would use a {} block to limit the borrow, but this seems to be not possible in match or if let.

What is the idiomatic way to end a borrow so that I can get a new mutable borrow?


This is not possible at the moment. What you want is called non-lexical borrows and it is yet to be implemented in Rust. Meanwhile, you should use Entry API to work with maps - in most cases it should be sufficient. In this particular case I'm not sure if entries are applicable, but you can always do something like

let mut result = None;
if let Some(&Node::LeafNode(ref leaf_node)) = self.pages.get(&page) {
    let mut leaf_node = leaf_node.clone();
    // ...
    result = Some((leaf_page, leaf_node));
}

if let Some((leaf_page, leaf_node)) = result {
    self.pages.insert(leaf_page, leaf_node);
}

It is difficult to make the code above entirely correct given that you didn't provide definitions of Node and self.pages, but it should be approximately right. Naturally, it would work only if leaf_page and leaf_node do not contain references to self.pages or self, otherwise you won't be able to access self.pages.