Loan validation error with a variable that does not live long enough in a nested lambda

I get an error message inside a nested lambda.

let rows = vec![ vec![3, 6, 2, 8, 9, 0], vec![0, 0, 1, 4, 5, 1], ]; let pair_sums = rows.iter() .flat_map(|row| { (0..row.len() - 1).map(|i| row[i] + row[i + 1]) }) .collect::<Vec<_>>(); println!("{:?}", pair_sums); 
 error[E0597]: `row` does not live long enough --> src/main.rs:9:40 | 9 | (0..row.len() - 1).map(|i| row[i] + row[i + 1]) | --- ^^^ does not live long enough | | | capture occurs here 10 | }) | - borrowed value only lives until here 11 | .collect::<Vec<_>>(); | - borrowed value needs to live until here 

I can understand why this is happening, and I can fix it by putting the row value on the inner lambda:

 let pair_sums = rows.iter() .flat_map(|row| { (0..row.len() - 1).zip(vec![row; row.len()]) .map(|(i, row)| row[i] + row[i + 1]) }) .collect::<Vec<_>>(); 

This is terrible and may not be the best solution. How can I refer to variables in the parent scope without having to pass them explicitly?

+5
source share
1 answer

The trick here is how closures fix their variables: they will refer to them if permitted by the contents of the closure, not looking at how they are used to keep the output local in the closure expression and predictive. In this case, the row variable is used only by reference, so it can be captured by reference; that is, the closure passed to the map contains a link to row . Thus, this object cannot leave the region declaring the row variable (i.e. flat_map ), because this link will flat_map to invalid memory. Returning .map(closure) will violate this rule, since .map creates a lazy iterator that saves the closure and only calls it as the elements are requested.

The fix is ​​to make the row variable not register by reference, so closing can leave the scope. This can be done using the keyword move :

 let pair_sums = rows.iter() .flat_map(|row| { (0..row.len() - 1) .map(move |i| row[i] + row[i + 1]) }) .collect::<Vec<_>>(); 

In other words, the source code is equivalent to something like:

 let pair_sums = rows.iter() .flat_map(|row: &Vec<i32>| { let row_ref: &&Vec<i32> = &row; (0..row.len() - 1) .map(move |i| (*row_ref)[i] + (*row_ref)[i + 1]) }) .collect::<Vec<_>>(); 

(My search for closure in rust after a more detailed search in closure, as well as the Book of Rust .)

+7
source

Source: https://habr.com/ru/post/1235497/


All Articles