变量在嵌套 lambda 中存活时间不够长的借用检查错误
Borrow-check error with variable not living long enough in nested lambda
我在嵌套的 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()).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
我有点明白为什么会这样,我可以通过将 row
的值线程化到内部 lambda 来修复它:
let pair_sums = rows.iter()
.flat_map(|row| {
(0 ..= row.len()).zip(iter::repeat(row))
.map(|(i, row)| row[i] + row[i + 1])
})
.collect::<Vec<_>>();
这太糟糕了,不是最好的解决方案。我如何才能在父作用域中引用变量而不必显式传递它们?
这里的技巧是闭包如何捕获它们的变量:如果闭包的内容允许,它们将引用它们,而不看它们是如何使用的,以保持闭包表达式的局部推理和可预见的。在这种情况下,row
变量仅通过引用使用,因此可以通过引用捕获;也就是说,传递给 map 的闭包对象包含对 row
的引用。因此,该对象不能离开声明 row
变量的范围(即 flat_map
的闭包),因为该引用将指向无效内存。返回 .map(closure)
将违反此规则,因为 .map
创建了一个惰性迭代器来存储闭包并仅在请求元素时调用它。
这里的修复是强制 row
变量不被引用捕获,这样闭包就可以离开作用域。这可以通过 move
关键字来完成:
let pair_sums = rows.iter()
.flat_map(|row| {
(0..row.len() - 1)
.map(move |i| row[i] + row[i + 1])
})
.collect::<Vec<_>>();
换句话说,原始代码相当于:
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<_>>();
(我的Finding Closure in Rust post digs into closures in more detail, as does the Rust book.)
我在嵌套的 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()).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
我有点明白为什么会这样,我可以通过将 row
的值线程化到内部 lambda 来修复它:
let pair_sums = rows.iter()
.flat_map(|row| {
(0 ..= row.len()).zip(iter::repeat(row))
.map(|(i, row)| row[i] + row[i + 1])
})
.collect::<Vec<_>>();
这太糟糕了,不是最好的解决方案。我如何才能在父作用域中引用变量而不必显式传递它们?
这里的技巧是闭包如何捕获它们的变量:如果闭包的内容允许,它们将引用它们,而不看它们是如何使用的,以保持闭包表达式的局部推理和可预见的。在这种情况下,row
变量仅通过引用使用,因此可以通过引用捕获;也就是说,传递给 map 的闭包对象包含对 row
的引用。因此,该对象不能离开声明 row
变量的范围(即 flat_map
的闭包),因为该引用将指向无效内存。返回 .map(closure)
将违反此规则,因为 .map
创建了一个惰性迭代器来存储闭包并仅在请求元素时调用它。
这里的修复是强制 row
变量不被引用捕获,这样闭包就可以离开作用域。这可以通过 move
关键字来完成:
let pair_sums = rows.iter()
.flat_map(|row| {
(0..row.len() - 1)
.map(move |i| row[i] + row[i + 1])
})
.collect::<Vec<_>>();
换句话说,原始代码相当于:
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<_>>();
(我的Finding Closure in Rust post digs into closures in more detail, as does the Rust book.)