Search code examples
rustclosures

Borrowed data escapes the closure


I am trying to copy a string outside of a closure by cloning it, but the compiler is telling me that k escapes the closure body.

I thought the clone would allow me to get around to this, but that does not work.

Any idea how I could achieve a behavior similar to the one describe hereafter? I am in reality trying to read off a file and yield each line in a closure, to maybe copy some of them.

fn copier(src: &Vec<&str>, mut closure: impl FnMut(&str) -> ()) {
    for s in src {
        closure(s);
    }
}

fn main() {
    let source: Vec::<&str> = vec!["aa", "bb"];
    let mut new_vec: Vec::<&str> = vec![];
    copier(&source, |k| new_vec.push(k.clone()));
    println!("{:?}", new_vec);
}

Error:

Standard Error
   Compiling playground v0.0.1 (/playground)
error[E0521]: borrowed data escapes outside of closure
  --> src/main.rs:10:25
   |
9  |     let mut new_vec: Vec::<&str> = vec![];
   |         ---------- `new_vec` declared here, outside of the closure body
10 |     copier(&source, |k| new_vec.push(k.clone()));
   |                      -  ^^^^^^^^^^^^^^^^^^^^^^ `k` escapes the closure body here
   |                      |
   |                      `k` is a reference that is only valid in the closure body

Solution

  • Oh! Thanks @Masklinn! I was copying the reference, not the content.

    This helps my understanding of memory management, I come from JS so there's a long way...

    Additionally, I needed to change the type of what new_vec contains to be String. If I understand well, I can't push an &str into it, because the String it refers to (created with the call to to_owned) gets dropped at the end of the closure.

    So the newly created Strings needs to move out of it.

    Updated solution:

    fn copier(src: &Vec<&str>, mut closure: impl FnMut(&str) -> ()) {
        for s in src {
            closure(s);
        }
    }
    
    fn main() {
        let source: Vec::<&str> = vec!["aa", "bb"];
        let mut new_vec: Vec::<String> = vec![];
        copier(&source, |k| new_vec.push(k.to_owned()));
        println!("{:?}", new_vec);
    }