这三个最常用的迭代器适配器,细节一点也不少:闭包拿到的是引用还是值?fold 的顺序有什么影响?出错能不能提前停?链写出来的机器码和手写循环一样吗?这篇都用真实编译与运行来回答。
源码:
1 | fn tn<T>(_: &T) -> &'static str { std::any::type_name::<T>() }
2 | fn main() {
3 | let v = vec![1, 2, 3, 4, 5, 6];
4 | let a: Vec<String> = v.iter().map(|x| format!("#{}", x)).collect();
5 | println!("map i32 -> String: {:?}", a);
6 | let b: Vec<&i32> = v.iter().filter(|x| { println!(" filter 闭包的参数类型 {}", tn(&x)); **x % 2 == 0 }).take(1).collect();
7 | println!("filter 之后元素类型仍是 &i32: {:?}", b);
8 | let c: Vec<i32> = v.iter().copied().filter(|x| x % 2 == 0).collect();
9 | println!("copied 之后 filter 参数是 &i32,可以直接 x % 2: {:?}", c);
10 | }
编译:成功
运行(退出码 0):
map i32 -> String: ["#1", "#2", "#3", "#4", "#5", "#6"]
filter 闭包的参数类型 &&i32
filter 闭包的参数类型 &&i32
filter 之后元素类型仍是 &i32: [2]
copied 之后 filter 参数是 &i32,可以直接 x % 2: [2, 4, 6]
源码:
1 | fn main() {
2 | let v = vec![1, 2, 3];
3 | let c: Vec<&i32> = v.iter().filter(|x| x % 2 == 0).collect();
4 | println!("{:?}", c);
5 | }
编译:失败
error[E0369]: cannot calculate the remainder of `&&{integer}` divided by `{integer}`
--> <实验目录>/src/u63b.rs:3:46
|
3 | let c: Vec<&i32> = v.iter().filter(|x| x % 2 == 0).collect();
| - ^ - {integer}
| |
| &&{integer}
|
help: `%` can be used on `&{integer}` if you dereference the left-hand side
|
3 | let c: Vec<&i32> = v.iter().filter(|x| *x % 2 == 0).collect();
| +
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0369`.惰性的具体含义见Iterator 的惰性执行。
编译:成功
运行(退出码 0):
filter_map(parse.ok): [10, 30, 50]
map(parse).flatten(): [10, 30, 50]
collect 成 Result: Err(ParseIntError { kind: InvalidDigit }) 编译:成功
运行(退出码 0):
fold(0, a*2+x) 从左到右: 48 rfold 从右到左: 24
fold 的累加器是 String(元素是 i32): "10-3-2"
fold 同时算 (和, 个数): (15, 3)
reduce(max): Some(10) 空序列 reduce: None 空序列 fold(0,..): 0
scan 保留中间状态: [10, 13, 15] 编译:成功
运行(退出码 0):
u8 的 checked_add:total None(看了 4 个元素,累加到第 4 个溢出)
不溢出的情形: Some(6) 汇编里的符号别名: [('_sum_iter', '_sum_fold')]
sum_for 指令 65 条 向量指令(.4s/.2d)条数 15
sum_fold 指令 60 条 向量指令(.4s/.2d)条数 15
sum_iter 指令 0 条 向量指令(.4s/.2d)条数 0
sum_map_filter 指令 95 条 向量指令(.4s/.2d)条数 39
sum_manual 指令 100 条 向量指令(.4s/.2d)条数 39
sum_for 与 sum_fold(规范化标签后)逐行相同: False; map+filter+fold 与手写循环逐行相同: False指令条数来自 aarch64 的 -O 汇编,换平台数字会不同。