在嵌套迭代器中指定生命周期以进行展平
Specifying lifetimes in nested iterators for flattening
我正在编写一个函数,它应该采用几个向量并将它们的笛卡尔积(它们的所有对组合)作为行优先顺序的向量。换句话说,如果我有
let x_coords = vec![1, 2, 3];
let y_coords = vec![4, 5, 6];
我要生产
vec![ [1,4], [1,5], [1,6], [2,4], [2,5], [2,6], [3,4], [3,5], [3,6] ]
这对 .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);
}
但这行不通,因为&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();
我唯一添加的是内部闭包前面的 move
关键字。为什么?下面让我们试着理解编译器在想什么!
一些注意事项:
- 我将
map
重命名为 flat_map
并删除了第二个 flat_map
调用...你让你的生活变得更加复杂 ;-)
- 我省略了
coord_vec
的部分类型注解,因为没必要
说明
类型 x_coord
是 i32
(或任何其他整数)。不是参考或任何东西,而是直接的价值。这意味着 x_coord
属于封闭函数,它恰好是一个闭包,特别是 "outer" 闭包,您传递给 flat_map
。因此 x_coord
只存在于闭包内,而不是更长。这就是编译器告诉你的。到目前为止一切顺利。
当您定义第二个闭包("inner" 闭包)时,您可以访问环境,特别是 x_coord
。现在的重要问题是:闭包如何访问它的环境?它可以通过不可变引用、可变引用和值来实现。 Rust 编译器确定需要什么样的环境访问权限,并选择有效的 "least intrusive" 选项。让我们看看你的代码:编译器发现闭包只需要不变地借用环境(因为 i32
是 Copy
因此闭包可以将其 &i32
转换为 i32
轻松)。
但在这种情况下,编译器的推理是错误的!借用其环境的闭包导致有限的生命周期。在这种情况下,我们需要闭包比它能活得更久,因此会出现错误。
通过添加 move
,我们强制编译器按值将环境传递给闭包(转移所有权)。这样闭包就不会借用任何东西并且可以永远存在(满足'static
)。
我正在编写一个函数,它应该采用几个向量并将它们的笛卡尔积(它们的所有对组合)作为行优先顺序的向量。换句话说,如果我有
let x_coords = vec![1, 2, 3];
let y_coords = vec![4, 5, 6];
我要生产
vec![ [1,4], [1,5], [1,6], [2,4], [2,5], [2,6], [3,4], [3,5], [3,6] ]
这对 .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);
}
但这行不通,因为&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();
我唯一添加的是内部闭包前面的 move
关键字。为什么?下面让我们试着理解编译器在想什么!
一些注意事项:
- 我将
map
重命名为flat_map
并删除了第二个flat_map
调用...你让你的生活变得更加复杂 ;-) - 我省略了
coord_vec
的部分类型注解,因为没必要
说明
类型 x_coord
是 i32
(或任何其他整数)。不是参考或任何东西,而是直接的价值。这意味着 x_coord
属于封闭函数,它恰好是一个闭包,特别是 "outer" 闭包,您传递给 flat_map
。因此 x_coord
只存在于闭包内,而不是更长。这就是编译器告诉你的。到目前为止一切顺利。
当您定义第二个闭包("inner" 闭包)时,您可以访问环境,特别是 x_coord
。现在的重要问题是:闭包如何访问它的环境?它可以通过不可变引用、可变引用和值来实现。 Rust 编译器确定需要什么样的环境访问权限,并选择有效的 "least intrusive" 选项。让我们看看你的代码:编译器发现闭包只需要不变地借用环境(因为 i32
是 Copy
因此闭包可以将其 &i32
转换为 i32
轻松)。
但在这种情况下,编译器的推理是错误的!借用其环境的闭包导致有限的生命周期。在这种情况下,我们需要闭包比它能活得更久,因此会出现错误。
通过添加 move
,我们强制编译器按值将环境传递给闭包(转移所有权)。这样闭包就不会借用任何东西并且可以永远存在(满足'static
)。