外观
第 5 节:迭代器 vs 手写循环——零成本抽象是真的
症状
新手(和老手)担心:"迭代器链那么多方法调用,是不是比手写 for 循环慢?"
诊断
不会。 Rust 的编译器会把迭代器链内联 + 优化回手写循环的样子——这就是第 11 章说过的零成本抽象:写起来高级,跑起来和低级写法一样快。
实测(100 万个数字,筛偶数求和,release 模式):
实测数据
text
手写循环:526 µs
迭代器链:481 µs
(迭代器反而略快)结果一样,迭代器还快了 8%(编译器优化得更彻底)。"用迭代器会慢"是都市传说。
解药
解药一:放心用迭代器链——filter/map/sum 的组合,和手写循环同速:
rust
// 手写循环
let mut sum = 0u64;
for &n in &numbers {
if n % 2 == 0 {
sum += n as u64;
}
}
// 迭代器(一样快,还更清晰)
let sum: u64 = numbers.iter()
.filter(|n| *n % 2 == 0)
.map(|&n| n as u64)
.sum();解药二:真正的"慢点"不在迭代器,在闭包里的重活——filter 闭包里的 expensive() 每元素都跑,map 里的分配每元素都发生:
rust
// 慢:每元素分配一个 String
let texts: Vec<String> = items.iter().map(|i| format!("{}", i)).collect();
// 快:数字直接算,不经过字符串
let total: u64 = items.iter().map(|i| i * 2).sum();预防
- "迭代器慢"的流言终结者:编译期内联优化是 Rust 的核心承诺(第 11 章 TRPL 名言:"闭包和迭代器的速度超乎想象")
- 性能瓶颈找别处:真慢的时候,查算法、查分配、查锁(第 2/3 节),别赖迭代器
- 例外:迭代器链里每步都调"外部重操作"(IO、网络)时,和手写循环一样慢——因为慢的是操作本身
- debug 模式下的迭代器可能略慢:dev 模式优化少,迭代器闭包内联不彻底——比性能永远用 release(第 4 节)