I'm writing a function to process Vec<Vec<i32>>
:
fn process_grid(grid: Vec<Vec<i32>>) -> Vec<i32> {
grid.iter()
.enumerate()
.flat_map(|(i, row)| {
row.iter()
.enumerate()
// closure may outlive the current function,
// but it borrows `i`, which is owned by the current function
.flat_map(|(j, val)| process(i, j, *val))
})
.collect()
}
fn process(i: usize, j: usize, val: i32) -> Option<i32> {
todo!()
}
The full compile error looks as follow:
error[E0373]: closure may outlive the current function, but it borrows `i`, which is owned by the current function
--> src/main.rs:291:27
|
291 | .flat_map(|(j, val)| process(i, j, *val))
| ^^^^^^^^^^ - `i` is borrowed here
| |
| may outlive borrowed value `i`
|
note: closure is returned here
--> src/main.rs:289:13
|
289 | / row.iter()
290 | | .enumerate()
291 | | .flat_map(|(j, val)| process(i, j, *val))
| |_________________________________________________________^
help: to force the closure to take ownership of `i` (and any other referenced variables), use the `move` keyword
|
291 | .flat_map(move |(j, val)| process(i, j, *val))
| ++++
Adding the move
keyword indeed make things work, but it didn't make it clear on why it does not compile without move.
How is it even possible the closure |(j, val)| process(i, j, *val)
may outlive its enclosing closure:
|(i, row)| {
row.iter()
.enumerate()
// closure may outlive the current function,
// but it borrows `i`, which is owned by the current function
.flat_map(|(j, val)| process(i, j, *val))
}
Maybe placing explicit lifetime would help here?
The compiler has chosen that the closure in question only references i
, and since that is captured by reference and iterators are lazy, this will effectively try to return a reference to i
from the outer flat_map
closure, which isn't allowed since i
only exists for that call.
In this case it is sufficient to tell the compiler to move captures into the closure by adding the move
keyword like so:
fn process_grid(grid: Vec<Vec<i32>>) -> Vec<i32> {
grid.iter()
.enumerate()
.flat_map(|(i, row)| {
row.iter()
.enumerate()
.flat_map(move |(j, val)| process(i, j, *val))
// ^^^^
})
.collect()
}