变量在嵌套 lambda 中生存时间不够长的借用检查错误

2024-05-20

我在嵌套 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<_>>();

(My 在 Rust 中寻找封闭 http://huonw.github.io/blog/2015/05/finding-closure-in-rust/帖子更详细地探讨了闭包,就像锈书 https://doc.rust-lang.org/book/first-edition/closures.html.)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

变量在嵌套 lambda 中生存时间不够长的借用检查错误 的相关文章

随机推荐