Passing a ref to a closure to .or_insert_with() consumes it right away

Hi fellow rustaceans :wave:

I can't make sense of the two examples below yielding different results:

  1. This one yields a compiler error: no method named 'calculation' found for mutable reference &mut Cacher<T, U, V> in the current scope.,
 fn value(&mut self, arg: U) -> &V {
        self.values.entry(arg).or_insert_with(|| &self.calculation(arg))
    }
  1. while this works as expected:
 fn value(&mut self, arg: U) -> &V {
        let calculation = &self.calculation;
        self.values.entry(arg).or_insert_with(|| calculation(arg))
    }

From what I understand, the first example consumes the closure right away, effectively resulting in an error, since, well, there isn't a closure anymore, only the resulting value.

I would have expected the two expressions to yield identical results and I can't wrap my head around why they don't :confused:

Would be great if anyone had any hints on that :upside_down_face:

I think you have found the right way to write your code for now. We can still talk about the details.

The first code needs a small fix to syntax. The right way to call a closure in a field is (self.calculation)(arg). This makes sure there is a difference between a method and a field called calculation - and here it is a field.

After that there's another problem, and solving that is in the plan: The Plan for the Rust 2021 Edition | Rust Blog

The Rust 2018 (current) edition's view of your code is that there is a conflict:

  • self.values is borrowed mutably to insert an item using entry
  • the closure wants to borrow self to call the calculation

As you know we can't have an outstanding mutable borrow at the same time as we want to have a shared borrow of self.

In Rust 2021 it should see that the closure just wants to borrow self.calculation, and then it should work - that doesn't overlap with self.values.

3 Likes

Wow! Things make a ton of sense now, thanks so much for taking the time :slight_smile: It's one thing to get code to work, it's another to understand why... Cheers!