在嵌套迭代器中指定生命周期以进行展平

bri*_*tar 3 iterator lifetime nested-loops rust

我正在编写一个函数,它应该采用几个向量并生成它们的笛卡尔积(它们的所有对组合)作为行主要顺序的向量.换句话说,如果我有

let x_coords = vec![1, 2, 3];
let y_coords = vec![4, 5, 6];
Run Code Online (Sandbox Code Playgroud)

我想生产

vec![ [1,4], [1,5], [1,6], [2,4], [2,5], [2,6], [3,4], [3,5], [3,6] ]
Run Code Online (Sandbox Code Playgroud)

这似乎是一个完美的工作.flat_map():

fn main() {
    let x_coords = vec![1, 2, 3];
    let y_coords = vec![4, 5, 6];

    let coord_vec: Vec<[isize; 2]> =
        x_coords.iter().map(|&x_coord| {
            y_coords.iter().map(|&y_coord| {
                [x_coord, y_coord]
            })
        }).flat_map(|s| s).collect();

    // Expecting to get: vec![ [1,4], [1,5], [1,6], [2,4], [2,5], [2,6], [3,4], [3,5], [3,6] ]
    println!("{:?}", &coord_vec);
}
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为&x_coord活得不够久.根据编译器,它最终在y_coords地图内部,然后永远不会让它退出.

我尝试使用.clone()move在闭包中,但编译器以多Note:行的形式进行了一个奇怪的长而不清楚的演讲.

我是完全偏离基础flat_map,还是可以保存?

Luk*_*odt 6

你真的很亲密!这有效:

let coord_vec: Vec<_> = x_coords.iter()
    .flat_map(|&x_coord| {
        y_coords.iter().map(move |&y_coord| {
        //                  ^^^^
            [x_coord, y_coord]
        })
    })
    .collect();
Run Code Online (Sandbox Code Playgroud)

我添加的唯一内容是move内部闭包前面的关键字.为什么?让我们试着理解下面编译器的想法!

但有几点说明:

  • 我改名mapflat_map并删除了第二个flat_map电话......你让你的生活更加复杂,比它是;-)
  • 我省略了部分类型注释coord_vec,因为它没有必要

说明

类型x_coordi32(或任何其他整数).不是参考或任何东西,而是直接的价值.这意味着它x_coord由封闭函数拥有,它恰好是一个闭包,特别是你传递给的"外部"闭包flat_map.因此,x_coord生活在关闭内部,而不是更长时间.这就是编译器告诉你的.到现在为止还挺好.

定义第二个闭包("内部"闭包)时,特别是访问环境x_coord.现在重要的问题是:关闭如何访问其环境?它可以使用不可变引用,可变引用和值来实现.Rust编译器确定需要对环境的访问类型,并选择有效的"最少侵入性"选项.让我们来看看你的代码:编译器发现闭包只需要不可变地借用环境(因为i32是因为Copy闭包可以很容易地将它&i32转换成一个i32).

但在这种情况下,编译器的推理是错误的!借用其环境的封闭导致有限的寿命.在这种情况下,我们需要闭包能够存活更长时间,因此错误.

通过添加move,我们强制编译器通过值将环境传递给闭包(转移所有权).这样封闭就没有借用,可以永远活着(满足'static).