Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why may a closure outlive the current function by borrowing a u32?

I’m getting

error[E0373]: closure may outlive the current function, but it borrows row_nr, which is owned by the current function

I would not expect this, since row_nr is a u32, so I’d expect it to be copied rather than moved:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel


fn get_neighbours(values: &Vec<Vec<u32>>, row: usize, col: usize) -> Vec<u32> {
    vec![
        values.get(row - 1).and_then(|cols| cols.get(col)),
        values.get(row).and_then(|cols| cols.get(col - 1)),
        values.get(row).and_then(|cols| cols.get(col + 1)),
        values.get(row + 1).and_then(|cols| cols.get(col)),
    ].into_iter().filter_map(|value_opt| value_opt.map(|value| *value)).collect()
}

fn get_points(values: Vec<Vec<u32>>) -> Vec<(u32, Vec<u32>)> {
    values
        .iter()
        .enumerate()
        .flat_map(|(row_nr, columns)| {
            columns.iter().enumerate().map(|(column_nr, height)| {
                let neighbours = get_neighbours(&values, row_nr, column_nr);
                (*height, neighbours)
            })
        }).collect()
}

Full error message:

  --> src/lib.rs:16:44
   |
16 |             columns.iter().enumerate().map(|(column_nr, height)| {
   |                                            ^^^^^^^^^^^^^^^^^^^^^ may outlive borrowed value `row_nr`
17 |                 let neighbours = get_neighbours(&values, row_nr, column_nr);
   |                                                          ------ `row_nr` is borrowed here
   |
note: closure is returned here
  --> src/lib.rs:16:13
   |
16 | /             columns.iter().enumerate().map(|(column_nr, height)| {
17 | |                 let neighbours = get_neighbours(&values, row_nr, column_nr);
18 | |                 (*height, neighbours)
19 | |             })
   | |______________^
help: to force the closure to take ownership of `row_nr` (and any other referenced variables), use the `move` keyword
   |
16 |             columns.iter().enumerate().map(move |(column_nr, height)| {
   |                                            ++++

See also on the Rust playground.

Now, the error suggest using move, but that becomes problematic because I’d only like to pass a reference to the values Vec (which I don’t think should outlive the closure, because get_neighbours takes u32s from that Vec and thus should make copies too, I think?).

I presume I’m misunderstanding lifetimes here. I’d appreciate any insights on what I’m misinterpreting. I looked at a couple of related questions, but they seem to either resolve it using a move (which, as mentioned above, I think I should (be able to) avoid?), or have multiple borrow checker issues, making it hard for me to understand which applies ones to me (e.g. this answer).

>Solution :

I would not expect this, since row_nr is a u32, so I’d expect it to be copied rather than moved

This expectation is correct, assuming it were moved in the first place. In this case it’s not moved, it’s borrowed, because by default closures borrow values from their environment. To request a move, which will for u32 indeed result in a copy, you need to use the move keyword explicitly.

As you discovered, when you just use move, you also move values, which doesn’t compile and is not what you want. The standard idiom to move only one value in Rust and to borrow another is to use move but add explicit borrows for the stuff you don’t want moved (values in your case). For example, this compiles:

.flat_map(|(row_nr, columns)| {
    columns.iter().enumerate().map({
        let values = &values;
        move |(column_nr, height)| {
            let neighbours = get_neighbours(values, row_nr, column_nr);
            (*height, neighbours)
        }
    })
})

Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading