嵌套数据怎么展开?flat_map 与 flatten 有什么区别?内层闭包为什么经常要加 move?它惰性到什么程度?这篇把二维数组、拆词、Option、笛卡尔积的展开和惰性计数、size_hint、性能一次跑清楚。
编译:成功
运行(退出码 0):
flat_map [1, 2, 3, 4, 5] / map+flatten [1, 2, 3, 4, 5] / flatten [1, 2, 3, 4, 5]
按行拆词: ["to", "be", "or", "not", "to", "be"]
字符: ['a', 'b', 'c', 'd']
flat_map 把 Option 当作 0 或 1 个元素: [1, 3]
一对多:每个数 n 展开成 1..=n: [1, 1, 2, 1, 2, 3]
笛卡尔积: [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]惰性的基础见Iterator 的惰性执行。
源码:
1 | fn main() {
2 | let v: Vec<(i32, i32)> = (1..=2).flat_map(|x| (1..=2).map(|y| (x, y))).collect();
3 | println!("{:?}", v);
4 | }
编译:失败
error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
--> <实验目录>/src/u65b.rs:2:63
|
2 | let v: Vec<(i32, i32)> = (1..=2).flat_map(|x| (1..=2).map(|y| (x, y))).collect();
| ^^^ - `x` is borrowed here
| |
| may outlive borrowed value `x`
|
note: closure is returned here
--> <实验目录>/src/u65b.rs:2:51
|
2 | let v: Vec<(i32, i32)> = (1..=2).flat_map(|x| (1..=2).map(|y| (x, y))).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
|
2 | let v: Vec<(i32, i32)> = (1..=2).flat_map(|x| (1..=2).map(move |y| (x, y))).collect();
| ++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0373`. 编译:成功
运行(退出码 0):
take(7) = [0, 0, 1, 0, 1, 2, 0]
内层迭代器创建了 4 个(外层有 1000 个),内层元素共产出 7 个 编译:成功
运行(退出码 0):
rev: [6, 5, 4, 3, 2, 1]
size_hint: flatten (0, None) / 单层 iter (3, Some(3))
flatten 在没开始消费时 size_hint 的下界 0 是真实元素数 6 吗? 否:展开前不知道内层长度
Result 展开丢弃 Err: [1, 3]size_hint 对 collect 预分配的影响见collect 类型推断。
编译:成功
运行(退出码 0):
flat_map 链 0.154 ms 双重 for 0.156 ms 先对每行 sum 再 sum 0.153 ms (结果 2570569 2570569 2570569)数字是本机 release 实测;数据很小(1M 个 u32),不同形状(很多很短的内层)可能不同,没有测。