Strange borrow checker behavior when returning content of Option

Let we have the code:

use std::collections::HashMap;

struct Fibonaccer {
   cache: HashMap<isize, isize>,
}

impl Fibonaccer {
  fn get(&mut self, i: isize)-> &isize {
    // if let Some(result) = self.cache.get(&i) {
    //  return result;
    // }

    // let get_result = self.cache.get(&i);
    // if get_result.is_some() {
    //   return get_result.unwrap();
    // }
    
    if self.cache.get(&i).is_some() {
      return self.cache.get(&i).unwrap();
    }

    let mut value = 1;
    if i > 2 {
      value = *self.get(i - 1) + *self.get(i - 2);
    }

    self.cache.entry(i).or_insert(value)
  }
}

Here we add value to cache and return reference to cached value. You can say that I can copy result, because it has tiny type, but in common case it can have huge type.

As you can see, I use very strange illogical way to return cached value. Both commented variants are not accepted by borrow checker:

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src\main.rs:24:16
   |
8  |   fn get(&mut self, i: isize)-> &isize {
   |          - let's call the lifetime of this reference `'1`
9  |     if let Some(result) = &self.cache.get(&i) {
   |                            ------------------ immutable borrow occurs here
10 |      return result;
   |             ------ returning this value requires that `self.cache` is borrowed for `'1`
...
24 |       value = *self.get(i - 1) + *self.get(i - 2);
   |                ^^^^^^^^^^^^^^^ mutable borrow occurs here

And... I dont understang, why first or second variant are worse than trird.

It's a short coming in the current generation borrow checker.

2 Likes

Thanks a lot, I will wait for the fix

Might be awhile...

Maybe that was just minimized example, but returning by value would also fix this case.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.