rustlazy-static

'cannot borrow `tree` as mutable more than once at a time' while using lazy_static


#[macro_use]
extern crate lazy_static;

extern crate alloc;
use alloc::collections::BTreeMap;
use alloc::vec::Vec;

fn get_vec<'a>(tree: &'a mut BTreeMap<&'a str, Vec<&'a u8>>, key: &'a str) -> &'a mut Vec<&'a u8> {
    if !tree.contains_key(key) {
        let v = Vec::new();
        tree.insert(key, v);
    }
    tree.get_mut(key).unwrap()
}

lazy_static! {
    static ref VALUES: [u8; 2] = [1, 2];
    static ref TEST_HASH: BTreeMap<&'static str, Vec<&'static u8>> = {
        let mut tree: BTreeMap<&str, Vec<&u8>> = BTreeMap::new();
        let key = "test_key";

        for value in VALUES.iter() {
            /*
            { // #1 Block: This work fine
                if !tree.contains_key(key) {
                    let v = Vec::new();
                    tree.insert(key, v);
                }
                let v = tree.get_mut(key).unwrap();
                v.push(&value);
            }
            */
            { // #2 Block: This is not work
                let v = get_vec(&mut tree, key);
                v.push(&value);
            }
        }
        tree
    };
}

fn main() {
    for (key, v) in &*TEST_HASH {
        println!("{} {:?}", key, v);
    }
}

Above is my test code, you might need cargo add lazy_static to add dependency for build it.

I tried build but got below error

error[E0499]: cannot borrow `tree` as mutable more than once at a time
  --> src/main.rs:34:33
   |
34 |                 let v = get_vec(&mut tree, key);
   |                                 ^^^^^^^^^ `tree` was mutably borrowed here in the previous iteration of the loop
...
38 |         tree
   |         ---- returning this value requires that `tree` is borrowed for `'static`

error[E0505]: cannot move out of `tree` because it is borrowed
  --> src/main.rs:38:9
   |
19 |         let mut tree: BTreeMap<&str, Vec<&u8>> = BTreeMap::new();
   |             -------- binding `tree` declared here
...
34 |                 let v = get_vec(&mut tree, key);
   |                                 --------- borrow of `tree` occurs here
...
38 |         tree
   |         ^^^^
   |         |
   |         move out of `tree` occurs here
   |         returning this value requires that `tree` is borrowed for `'static`

Some errors have detailed explanations: E0499, E0505.
For more information about an error, try `rustc --explain E0499`.

This is a small program for getting vec from map.

My question is. (maybe both question is same)

  1. What is a problem?

  2. What is different between #Block1 and #Block2

I tried to find proper life cycle annotation but it wasn't work


Solution

  • The lifetimes in your get_vec function are too restrictive. By using a single lifetime for everything, you tie the lifetime of the keys and values to the lifetime of the map itself.

    You need at least two lifetimes, but for the most general solution, use three:

    fn get_vec<'map, 'key, 'elem>(tree: &'map mut BTreeMap<&'key str, Vec<&'elem u8>>, key: &'key str) -> &'map mut Vec<&'elem u8> {
        if !tree.contains_key(key) {
            let v = Vec::new();
            tree.insert(key, v);
        }
        tree.get_mut(key).unwrap()
    }
    

    playground