How to work around self borrowing with map .or_insert_with? Rust (1.11)

dictionary, rust

Solution

The problem is that the closure captures `self`, whereas it only needs to capture a mutable reference to the `last_id` field.

Rust allows us to take independent mutable borrows on distinct fields, so we can use that to our advantage and pass a mutable reference to the `last_id` field to the closure.

use std::collections::HashMap;

struct Foo {
    local_ids: HashMap<i32, i32>,
    last_id: i32,
}

impl Foo {
    fn foo(&mut self, external_id: i32) {
        let last_id = &mut self.last_id;
        let id = self.local_ids
                     .entry(external_id)
                     .or_insert_with(|| { *last_id += 1; *last_id });
    }
}

When we use the expression `self.last_id` in the closure, the closure captures `self` directly, but Rust doesn't realize that the borrows are independent, so we need to be more explicit.

Problem

This snippet ``` use std::collections::HashMap; struct Foo { local_ids: HashMap<i32, i32>, last_id: i32, } impl Foo { fn foo(&mut self, external_id: i32) { let id = self.local_ids .entry(external_id) .or_insert_with(||{self.last_id += 1; self.last_id}); } } ``` Doesn't work because we can't borrow self twice ``` error: closure requires unique access to `self` but `self.local_ids` is already borrowed [E0500] ``` Is this possible to fix without a second key lookup? This is very similar to Rust: HashMap borrow issue when trying to implement find or insert, but the API has changed substantially. The find_with_or_insert_with answer from above doesn't appear to map to the current api.

Original source

Related problems