借入检查错误,变量在嵌套lambda中的寿命不足 [英] Borrow-check error with variable not living long enough in nested lambda
问题描述
我在嵌套的lambda中遇到错误.
I am getting an error 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()).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来对其进行修复:
I can sort of see why this is happening, and I can fix it by threading the value of row
through to the inner 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<_>>();
这太可怕了,而且不是最好的解决方案.如何在父范围中引用变量而不必显式传递变量?
This is horrible and can't be the best solution. How can I refer to variables in a parent scope without having to pass them along explicitly?
推荐答案
这里的窍门是闭包如何捕获其变量:如果闭包的内容允许,它们将引用它们,而无需查看它们的方式用于保持推断局部于闭包表达式且可预测.在这种情况下,row
变量仅由引用使用,因此可以通过引用捕获.也就是说,传递给map的闭包对象包含对row
的引用.因此,此对象不能离开声明row
变量的作用域(即flat_map
的闭包),因为该引用将指向无效的内存.返回.map(closure)
将违反此规则,因为.map
创建一个懒惰的迭代器来存储闭包,并且仅在请求元素时调用它.
The trick here is how closures capture their variables: they will take references to them if it is allowed by the contents of the closure, without looking at how they are used, to keep the inference local to the closure expression and predicable. In this case the row
variable is only ever used by reference, so it is fine to be captured by reference; that is, the closure object passed to map contains a reference to row
. This object hence cannot leave the scope that declares the row
variable (i.e. flat_map
's closure) because that reference would be left pointing to invalid memory. Returning .map(closure)
will fall foul of this rule, as .map
creates a lazy iterator that stores the closure and only calls it as elements are requested.
此处的解决方法是强制row
变量不被引用捕获,以便闭包可以离开范围.这可以通过move
关键字完成:
The fix here is to force the row
variable to not be captured by reference, so that the closure can leave the scope. This can be done with the move
keyword:
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 original 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<_>>();
(我的在Rust中找到闭包 post更详细地介绍了闭包,锈皮书.)
(My Finding Closure in Rust post digs into closures in more detail, as does the Rust book.)
这篇关于借入检查错误,变量在嵌套lambda中的寿命不足的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!