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,还是可以保存?
你真的很亲密!这有效:
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内部闭包前面的关键字.为什么?让我们试着理解下面编译器的想法!
但有几点说明:
map到flat_map并删除了第二个flat_map电话......你让你的生活更加复杂,比它是;-)coord_vec,因为它没有必要类型x_coord是i32(或任何其他整数).不是参考或任何东西,而是直接的价值.这意味着它x_coord由封闭函数拥有,它恰好是一个闭包,特别是你传递给的"外部"闭包flat_map.因此,x_coord生活在关闭内部,而不是更长时间.这就是编译器告诉你的.到现在为止还挺好.
定义第二个闭包("内部"闭包)时,特别是访问环境x_coord.现在重要的问题是:关闭如何访问其环境?它可以使用不可变引用,可变引用和值来实现.Rust编译器确定需要对环境的访问类型,并选择有效的"最少侵入性"选项.让我们来看看你的代码:编译器发现闭包只需要不可变地借用环境(因为i32是因为Copy闭包可以很容易地将它&i32转换成一个i32).
但在这种情况下,编译器的推理是错误的!借用其环境的封闭导致有限的寿命.在这种情况下,我们需要闭包能够存活更长时间,因此错误.
通过添加move,我们强制编译器通过值将环境传递给闭包(转移所有权).这样封闭就没有借用,可以永远活着(满足'static).