Search code examples
rusthashmapclosuresborrow-checkercloning

Rust cloning HashMap<String, Object> without moving into closure


I am trying to make my own programming language in rust, and most features are done, so I thought I could add to the UnknownIdentifier error the ability to find the closest match to whatever the user wanted

However before I even got to finding the closest match I found out that cloning HashMap<String, Object> moves it into the closure

ErrorGenerator::error function:

#[allow(non_snake_case)]
mod ErrorGenerator {
    pub fn error(name: &str, explanation: &str, line: usize, col: usize, file: String, after_f: Box<dyn Fn() -> ()>) -> ! {
        eprintln!("\n[ERROR] {}, Line {:?}, Column {:?}", file, line, col);
        eprintln!("    {}: {}", name, explanation);
        after_f();
        exit(1);
    }
}
ErrorGenerator::error(
    "UnknownIdentifier",
    &format!("unknown identifier: `{}`, this identifier could not be found", tokenc.repr()),
    tokenc.line,
    tokenc.col,
    tokenc.file,
    Box::new(||{
        let mut hashc: Vec<String> = hashs.clone().into_keys().collect();
        hashc.sort();
    }),
);

This is the error it gives:

error[E0597]: `hashs` does not live long enough
    --> src/runtime/runtime.rs:960:70
     |
959  |                                       Box::new(||{
     |                                       -        -- value captured here
     |  _____________________________________|
     | |
960  | |                                         let mut hashc: Vec<String> = hashs.clone().into_keys().collect();
     | |                                                                      ^^^^^ borrowed value does not live long enough
961  | |                                         hashc.sort();
962  | |                                     }),
     | |______________________________________- cast requires that `hashs` is borrowed for `'static`
...
1203 |       }
     |       - `hashs` dropped here while still borrowed

The problem's solution is probably either:

  • A way to borrow in 'static lifetime a mutable variable created in a method into a closure or
  • A way to clone HashMap<String, Object> without moving it into the closure

You can find the full code in https://github.com/kaiserthe13th/tr-lang/tree/unknown-id-err-impl


Solution

  • What happens is that the compiler doesn't clone hashs then passes the clone to your callback; instead, it passes a reference to hashs to your callback and clones it inside the callback.

    However, the callback is required to be 'static, and if it holds a reference to the containing function it is not! So the compiler is complaining.

    What you want is to clone the hashmap before, then pass the clone to the callback. Like:

    ErrorGenerator::error(
        "UnknownIdentifier",
        &format!("unknown identifier: `{}`, this identifier could not be found", tokenc.repr()),
        tokenc.line,
        tokenc.col,
        tokenc.file,
        {
            let hashc = hashs.clone();
            Box::new(|| {
                let mut hashc: Vec<String> = hashc.into_keys().collect();
                hashc.sort();
            })
        },
    );
    

    If you'll do that, you'll also recognize that the closure needs to be FnOnce() since you're moving out of hashc (.into_keys()). So after_f: Box<dyn FnOnce()>.