Rust 迭代器

惰性求值、适配器与消费者、自定义迭代器、以及性能。

Intermediate
Key Points适配器(`map`/`filter`)是惰性的,只有消费者(`collect`/`sum`)才真正执行。

惰性求值

Rust
fn main() {
    let v = vec![1, 2, 3, 4, 5];

    // 这里什么都没算
    let iter = v.iter().map(|x| {
        println!("计算 {}", x);
        x * 2
    });

    println!("--- 还没开始 ---");

    // 消费者触发执行
    let doubled: Vec<i32> = iter.collect();
    println!("{:?}", doubled);
}
Output
--- 还没开始 ---
计算 1
计算 2
计算 3
计算 4
计算 5
[2, 4, 6, 8, 10]

Adapters only describe work and execute nothing. Two benefits: chains compose without intermediate collections, and the compiler fuses the whole chain into one loop.

常用适配器

MethodEffect
map转换每个元素
filter保留满足条件的
filter_map转换 + 过滤 Option
flat_map转换并展平
take / skip取前 n 个 / 跳过前 n 个
take_while取到条件不成立为止
chain拼接两个迭代器
zip配对
enumerate加上下标
rev反转
peekable可预读下一个
Rust
fn main() {
    let v = vec![1, 2, 3, 4, 5, 6];

    let r: Vec<i32> = v.iter()
        .filter(|&&x| x % 2 == 0)
        .map(|&x| x * x)
        .collect();
    println!("{:?}", r);

    for (i, x) in v.iter().enumerate().take(3) {
        print!("{}:{} ", i, x);
    }
    println!();
}
Output
[4, 16, 36]
0:1 1:2 2:3 

消费者

Rust
fn main() {
    let v = vec![1, 2, 3, 4, 5];

    println!("{}", v.iter().sum::<i32>());
    println!("{}", v.iter().product::<i32>());
    println!("{:?}", v.iter().max());
    println!("{:?}", v.iter().min());
    println!("{}", v.iter().count());
    println!("{}", v.iter().any(|&x| x > 4));
    println!("{}", v.iter().all(|&x| x > 0));
    println!("{:?}", v.iter().find(|&&x| x % 3 == 0));
    println!("{:?}", v.iter().position(|&x| x == 3));

    let s: String = v.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
    println!("{}", s);
}
Output
15
120
Some(5)
Some(1)
5
true
true
Some(3)
Some(2)
1,2,3,4,5

自定义迭代器

Rust
struct Counter {
    count: u32,
    max: u32,
}

impl Counter {
    fn new(max: u32) -> Self {
        Counter { count: 0, max }
    }
}

impl Iterator for Counter {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        if self.count < self.max {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

fn main() {
    let v: Vec<u32> = Counter::new(5).collect();
    println!("{:?}", v);

    let sum: u32 = Counter::new(4).filter(|x| x % 2 == 0).sum();
    println!("{}", sum);
}
Output
[1, 2, 3, 4, 5]
6

Implementing Iterator needs only next(); the dozens of other methods are default implementations you get for free. One of the prettiest uses of trait defaults.

性能

Rust
// 这两种写法编译后的机器码基本相同
let sum1: i32 = (1..=100).filter(|x| x % 2 == 0).sum();

let mut sum2 = 0;
for x in 1..=100 {
    if x % 2 == 0 {
        sum2 += x;
    }
}

"Zero-cost abstraction" shows up here: the chain is inlined and fused into a single loop with no call overhead and no intermediate Vec. So do not avoid iterators for performance.

iter() borrows (&T), into_iter() consumes and yields T, iter_mut() yields &mut T. for x in v is into_iter() — which is why it moves v.

Friends & Partners