It is not possible to take the immutable borrowed HashMap cache as mutable in a recursive Fibonacci implementation

I want to implement a Fibonacci series along with caching already calculated results. I'm not sure that this approach is possible even in Rust, but this is the best I came up with. Here is the code:

use std::collections::HashMap;

pub fn fib_hash(n: u32) -> u64 {
    let mut map: HashMap<u32, u64> = HashMap::new();

    // This is the engine which recurses saving each value in the map
    fn f(map: &HashMap<u32, u64>, n: u32) -> u64 {
        let c = match map.get(&n) {
            Some(&number) => number,
            _ => 0,
        };
        if c != 0 {
            return c;
        }
        let m = match n {
            1 if n < 1 => 0,
            1...2 => 1,
            _ => f(&map, n - 1) + f(&map, n - 2),
        };
        map.insert(n, m);
        m
    }
    f(&map, n)
}

The idea is to have a β€œglobal” one HashMapthat can be reused. However, I assume that this is actually not possible, as we will have several volatile borrowers for the card. This is the error I get

Rust 2015

error[E0596]: cannot borrow immutable borrowed content '*map' as mutable
  --> src/lib.rs:20:9
   |
7  |     fn f(map: &HashMap<u32, u64>, n: u32) -> u64 {
   |               ------------------ use '&mut HashMap<u32, u64>' here to make mutable
...
20 |         map.insert(n, m);
   |         ^^^ cannot borrow as mutable

Rust 2018

error[E0596]: cannot borrow '*map' as mutable, as it is behind a '&' reference
  --> src/lib.rs:20:9
   |
7  |     fn f(map: &HashMap<u32, u64>, n: u32) -> u64 {
   |               ------------------ help: consider changing this to be a mutable reference: '&mut std::collections::HashMap<u32, u64>'
...
20 |         map.insert(n, m);
   |         ^^^ 'map' is a '&' reference, so the data it refers to cannot be borrowed as mutable

Can I use this approach in Rust? What would be the best solution to this problem?

+4
source share
2 answers

map f &HashMap<u32, u64>, , get , HashMap. &mut HashMap<u32, u64> map, , . &mut map &map.

, . .

pub fn fib_hash(n: u32) -> u64 {
    // This is the engine which recurses saving each value in the map
    fn f(map: HashMap<u32, u64>, n: u32) -> (HashMap<u32, u64>, u64) {
        if let Some(&number) = map.get(&n) {
            return (map, number);
        }
        let (map, a) = f(map, n - 1);
        let (mut map, b) = f(map, n - 2);
        let res = a + b;
        map.insert(n, res);
        (map, res)
    }
    let mut map = HashMap::new();
    map.insert(0, 0);
    map.insert(1, 1);
    map.insert(2, 1);
    f(map, n).1
}

+7

, map ( ):

use std::collections::HashMap;

fn fib<'a>(n: u32, memo: &'a mut HashMap<u32, u32>) -> u32 {
    if n <= 2 {
        return 1;
    }

    return match memo.get(&n) {
        Some(&sum) => sum,
        None => {
            let new_fib_sum = fib(n - 1, memo) + fib(n - 2, memo);
            memo.insert(n, new_fib_sum);
            new_fib_sum
        }
    };
}

fn main() {
    let mut memo: HashMap<u32, u32> = HashMap::new();
    let n = 10; //or user input...or whatever
    print!("{}", fib(n, &mut memo));
}
+2

All Articles