1

I've been working through the book and am stuck on an exercise. In chapter 13.1, I'm trying to add generic types and the ability to cache multiple values to the memoization cacher. However, I'm getting a borrow error I don't understand.

It seems to me that the immutable borrow within the if let statement should go out of scope before the mutable borrow happens. I've tried enclosing the whole thing in a block but still no cigar. Could someone explain to me the error and recommend a solution?

Thanks in advance.

The code:

use std::collections::HashMap;
use std::hash::Hash;

struct Cacher<T, I, O>
where
    T: Fn(&I) -> O,
    I: Hash + Eq + Clone,
{
    func: T,
    values: HashMap<I, O>,
}

impl<T, I, O> Cacher<T, I, O>
where
    T: Fn(&I) -> O,
    I: Hash + Eq + Clone,
{
    fn new(func: T) -> Cacher<T, I, O> {
        Cacher {
            func,
            values: HashMap::new(),
        }
    }

    fn get(&mut self, arg: I) -> &O {
        if let Some(res) = self.values.get(&arg) {
            return &res;
        }

        self.values.insert(arg.clone(), (self.func)(&arg));
        self.values.get(&arg).unwrap()
    }
}

And the error:

error[E0502]: cannot borrow `self.values` as mutable because it is also borrowed as immutable
  --> src/lib.rs:30:9
   |
25 |     fn get(&mut self, arg: I) -> &O {
   |            - let's call the lifetime of this reference `'1`
26 |         if let Some(res) = self.values.get(&arg) {
   |                            ----------- immutable borrow occurs here
27 |             return &res;
   |                    ---- returning this value requires that `self.values` is borrowed for `'1`
...
30 |         self.values.insert(arg.clone(), (self.func)(&arg));
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
Stargateur
  • 24,473
  • 8
  • 65
  • 91
Jack Bishop
  • 115
  • 1
  • 7
  • 1
    https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=328eebfe8b273d707e6fb38af735dcbb, the explanation is out of my skill. It's a sort of limitation I think. Could compile in future – Stargateur Sep 03 '19 at 01:27
  • The error is the compiler is simply not smart enough to realize that only one mutable borrow could occur at a time. – Alex Huszagh Sep 03 '19 at 01:29
  • 1
    Thanks for the explanation and the link. The entry fix works perfectly and is much more concise than my original solution. – Jack Bishop Sep 03 '19 at 01:57
  • For future visitors ... see https://stackoverflow.com/a/28512504/1411457 for an example of the using the Entry API – harmic Sep 03 '19 at 02:02
  • From what I've read on this issue, shouldn't it have been fixed by the introduction of non-lexical lifetimes? I'm using the 2018 edition. – Jack Bishop Sep 03 '19 at 02:21
  • @JackBishop As explained in the answer, current implementation of NLL doesn't yet support this. – Stargateur Sep 03 '19 at 07:53

0 Answers0