云计算百科
云计算领域专业知识百科平台

【Rust入门知识点】第23课:迭代器 Iterators

知识点:迭代器基础

Rust 的迭代器是惰性的——创建迭代器本身不做任何事,只有消费它时才产生值:

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

// 三种迭代方式
// 1. iter():不可变借用
for n in numbers.iter() {
print!("{} ", n); // 1 2 3 4 5
}
println!();

// 2. iter_mut():可变借用
let mut nums = vec![1, 2, 3];
for n in nums.iter_mut() {
*n *= 10;
}
println!("可变迭代: {:?}", nums); // [10, 20, 30]

// 3. into_iter():获取所有权(消费集合)
let words = vec![String::from("hello"), String::from("world")];
for w in words.into_iter() {
println!("单词: {}", w);
}
// println!("{:?}", words); // ❌ words 已被消费

// 手动使用迭代器
let mut iter = vec![10, 20, 30].into_iter();
println!("{:?}", iter.next()); // Some(10)
println!("{:?}", iter.next()); // Some(20)
println!("{:?}", iter.next()); // Some(30)
println!("{:?}", iter.next()); // None
}

知识点:迭代器适配器(Adaptor)

适配器消费一个迭代器,返回一个新迭代器。它们是惰性的,不会立即执行:

fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// map:对每个元素做变换
let doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();
println!("翻倍: {:?}", doubled);

// filter:过滤元素
let evens: Vec<&i32> = numbers.iter().filter(|x| *x % 2 == 0).collect();
println!("偶数: {:?}", evens);

// enumerate:附带索引
let indexed: Vec<(usize, &i32)> = numbers.iter().enumerate().collect();
println!("带索引: {:?}", indexed);

// zip:把两个迭代器配对
let names = vec!["Alice", "Bob", "Charlie"];
let scores = vec![90, 85, 95];
let paired: Vec<(&&str, &i32)> = names.iter().zip(scores.iter()).collect();
println!("配对: {:?}", paired);

// take / skip
let first_three: Vec<&i32> = numbers.iter().take(3).collect();
let skip_two: Vec<&i32> = numbers.iter().skip(2).collect();
println!("前3个: {:?}", first_three);
println!("跳过2个: {:?}", skip_two);

// chain:连接两个迭代器
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
let chained: Vec<&i32> = a.iter().chain(b.iter()).collect();
println!("连接: {:?}", chained);

// peekable:可窥视的迭代器
let mut peekable = vec![1, 2, 3].into_iter().peekable();
println!("窥视: {:?}", peekable.peek()); // Some(1),不消费
println!("下一个: {:?}", peekable.next()); // Some(1),消费了
println!("再窥视: {:?}", peekable.peek()); // Some(2)
}

知识点:消费适配器(Consumer)

消费适配器会执行迭代并产生最终值:

fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// fold:带初始值的累积
let sum: i32 = numbers.iter().fold(0, |acc, x| acc + x);
println!("fold 求和: {}", sum); // 55

// reduce:不带初始值(返回 Option)
let max: Option<&i32> = numbers.iter().reduce(|a, b| if a > b { a } else { b });
println!("reduce 最大值: {:?}", max);

// count:计数
let count = numbers.iter().filter(|x| *x % 2 == 0).count();
println!("偶数个数: {}", count); // 5

// sum / product
let sum: i32 = numbers.iter().sum();
let product: i32 = numbers.iter().product();
println!("sum: {}, product: {}", sum, product);

// any / all
let has_even = numbers.iter().any(|x| x % 2 == 0);
let all_positive = numbers.iter().all(|x| *x > 0);
println!("有偶数: {}, 全正数: {}", has_even, all_positive);

// find:找到第一个满足条件的
let first_big = numbers.iter().find(|&&x| x > 7);
println!("第一个大于7的: {:?}", first_big); // Some(8)

// position:找到第一个满足条件的索引
let pos = numbers.iter().position(|&x| x > 7);
println!("第一个大于7的索引: {:?}", pos); // Some(7)

// min / max
let min = numbers.iter().min();
let max = numbers.iter().max();
println!("最小: {:?}, 最大: {:?}", min, max);

// for_each:对每个元素执行操作(不产生新值)
numbers.iter().for_each(|x| print!("{} ", x));
println!();
}

知识点:链式调用

迭代器最强大的地方是可以链式组合多个操作:

fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 链式调用:过滤 -> 变换 -> 收集
let result: Vec<i32> = numbers.iter()
.filter(|x| *x % 2 == 0) // 偶数
.map(|x| x * x) // 平方
.collect();
println!("偶数的平方: {:?}", result); // [4, 16, 36, 64, 100]

// 复杂链式:求偶数的平方和
let sum_of_squares: i32 = numbers.iter()
.filter(|x| *x % 2 == 0)
.map(|x| x * x)
.sum();
println!("偶数的平方和: {}", sum_of_squares); // 220

// flatMap:展平嵌套集合
let nested = vec![vec![1, 2, 3], vec![4, 5], vec![6, 7, 8, 9]];
let flat: Vec<&i32> = nested.iter()
.flat_map(|inner| inner.iter())
.collect();
println!("展平: {:?}", flat);

// 实战:统计一段文本中每个单词出现的次数
let text = "hello world hello rust world hello";
let mut word_counts = std::collections::HashMap::new();
text.split_whitespace()
.for_each(|word| {
*word_counts.entry(word).or_insert(0) += 1;
});
println!("词频: {:?}", word_counts);

// 实战:找到成绩最高的学生
let students = vec![
("Alice", 85),
("Bob", 92),
("Charlie", 78),
("Diana", 95),
];
let best = students.iter()
.max_by_key(|&&(_, score)| score);
println!("最高分学生: {:?}", best);

// 实战:分组统计
let scores = vec![45, 82, 91, 67, 55, 73, 88, 34, 96, 61];
let (pass, fail): (Vec<&i32>, Vec<&i32>) = scores.iter()
.partition(|&&score| score >= 60);
println!("及格: {:?}", pass);
println!("不及格: {:?}", fail);
}

知识点:自定义迭代器

实现 Iterator trait 来创建自定义迭代器:

// 自定义:斐波那契数列迭代器
struct Fibonacci {
a: u64,
b: u64,
}

impl Fibonacci {
fn new() -> Self {
Fibonacci { a: 0, b: 1 }
}
}

impl Iterator for Fibonacci {
type Item = u64;

fn next(&mut self) -> Option<Self::Item> {
let result = self.a;
let new_b = self.a + self.b;
self.a = self.b;
self.b = new_b;
Some(result)
}
}

// 自定义:范围迭代器(类似 std::ops::Range)
struct MyRange {
current: i32,
end: i32,
}

impl MyRange {
fn new(start: i32, end: i32) -> Self {
MyRange { current: start, end }
}
}

impl Iterator for MyRange {
type Item = i32;

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

fn main() {
// 使用自定义迭代器
let fibs: Vec<u64> = Fibonacci::new().take(10).collect();
println!("斐波那契: {:?}", fibs);
// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

// 斐波那契数列中偶数项的和(小于100)
let even_fib_sum: u64 = Fibonacci::new()
.take_while(|&x| x < 100)
.filter(|x| x % 2 == 0)
.sum();
println!("小于100的偶数斐波那契和: {}", even_fib_sum);

// 使用自定义范围
let range: Vec<i32> = MyRange::new(1, 6).collect();
println!("自定义范围: {:?}", range); // [1, 2, 3, 4, 5]

// 迭代器可以用于 for 循环
for n in MyRange::new(1, 4) {
print!("{} ", n);
}
println!();
}

核心规则

概念 写法 不可变迭代 collection.iter() 可变迭代 collection.iter_mut() 所有权迭代 collection.into_iter() 变换 .map( x …) 过滤 .filter( x …) 累积 .fold(init, acc, x …) 收集 .collect() 展平 .flat_map( x …) 分组 .partition( x …) 查找 .find( x …) / .position( x …) 自定义迭代器 impl Iterator for MyType { type Item = T; fn next(…) } 惰性求值 适配器不执行,消费器触发执行

动手试试

补全下面的代码:

// 补全:定义一个自定义迭代器 Counter
// 从 start 开始,每次递增 step
// 当值超过 end 时停止(不含 end)
// 例如 Counter::new(0, 10, 3) 产生 0, 3, 6, 9
struct Counter {
// 补全字段
}

impl Counter {
fn new(start: i32, end: i32, step: i32) -> Self {
// 补全
todo!()
}
}

// 补全:为 Counter 实现 Iterator trait
// type Item = i32

// 补全:实现函数 top_n_scores
// 接受一个 (姓名, 分数) 的切片和 n
// 返回分数最高的 n 个学生的姓名(按分数从高到低)
fn top_n_scores<'a>(students: &'a [(&'a str, i32)], n: usize) -> Vec<&'a str> {
// 补全:用迭代器链式调用实现
// 提示:sorted_by_key 或 sort + iter
todo!()
}

// 补全:实现函数 group_by_length
// 接受一个字符串切片,按字符串长度分组
// 返回 HashMap<usize, Vec<&str>>,键为长度,值为该长度的所有字符串
fn group_by_length<'a>(words: &'a [&'a str]) -> std::collections::HashMap<usize, Vec<&'a str>> {
// 补全:用迭代器实现
todo!()
}

// 补全:实现函数 running_average
// 接受一个浮点数切片,返回每个位置为止的_running average
// 例如 [1.0, 3.0, 5.0] => [1.0, 2.0, 3.0]
// 第1个: 1.0/1 = 1.0
// 第2个: (1.0+3.0)/2 = 2.0
// 第3个: (1.0+3.0+5.0)/3 = 3.0
fn running_average(numbers: &[f64]) -> Vec<f64> {
// 补全:用迭代器的 scan 或 enumerate + map 实现
todo!()
}

fn main() {
// 测试 Counter
let counter: Vec<i32> = Counter::new(0, 10, 3).collect();
println!("Counter(0,10,3): {:?}", counter);
// 期望: [0, 3, 6, 9]

let counter2: Vec<i32> = Counter::new(1, 20, 5).collect();
println!("Counter(1,20,5): {:?}", counter2);
// 期望: [1, 6, 11, 16]

// 测试 top_n_scores
let students = vec![
("Alice", 85),
("Bob", 92),
("Charlie", 78),
("Diana", 95),
("Eve", 88),
];
let top2 = top_n_scores(&students, 2);
println!("前2名: {:?}", top2);
// 期望: ["Diana", "Bob"]

// 测试 group_by_length
let words = vec!["hi", "hello", "hey", "world", "ok", "rust"];
let grouped = group_by_length(&words);
// 补全:按长度排序打印
// 期望:
// 长度2: ["hi", "ok"]
// 长度3: ["hey"]
// 长度4: ["rust"]
// 长度5: ["hello", "world"]

// 测试 running_average
let nums = vec![1.0, 3.0, 5.0, 7.0, 9.0];
let avgs = running_average(&nums);
println!("移动平均: {:?}", avgs);
// 期望: [1.0, 2.0, 3.0, 4.0, 5.0]
}

期望输出: Counter(0,10,3): [0, 3, 6, 9] Counter(1,20,5): [1, 6, 11, 16] 前2名: [“Diana”, “Bob”] 长度2: [“hi”, “ok”] 长度3: [“hey”] 长度4: [“rust”] 长度5: [“hello”, “world”] 移动平均: [1.0, 2.0, 3.0, 4.0, 5.0]

写好了贴过来,没问题就进入第24课:生命周期 Lifetimes 👋

贴代码

use std::collections::HashMap;

// 自定义迭代器 Counter
struct Counter {
current: i32,
end: i32,
step: i32,
}

impl Counter {
fn new(start: i32, end: i32, step: i32) -> Self {
Counter {
current: start,
end,
step,
}
}
}

// 实现 Iterator trait
impl Iterator for Counter {
type Item = i32;

fn next(&mut self) -> Option<Self::Item> {
if self.current >= self.end {
return None;
}
let val = self.current;
self.current += self.step;
Some(val)
}
}

/// 获取分数最高前n名学生姓名(分数降序)
fn top_n_scores<'a>(students: &'a [(&'a str, i32)], n: usize) -> Vec<&'a str> {
students
.iter()
.sort_by_key(|(_, score)| std::cmp::Reverse(*score));
students
.iter()
.take(n)
.map(|(name, _)| *name)
.collect()
}

/// 按字符串长度分组
fn group_by_length<'a>(words: &'a [&'a str]) -> HashMap<usize, Vec<&'a str>> {
words.iter().fold(HashMap::new(), |mut map, w| {
map.entry(w.len()).or_default().push(*w);
map
})
}

/// 前缀(滚动)平均值,使用scan实现
fn running_average(numbers: &[f64]) -> Vec<f64> {
numbers
.iter()
.scan((0.0, 0), |(sum, count), &val| {
*sum += val;
*count += 1;
Some(*sum / (*count as f64))
})
.collect()
}

fn main() {
// 测试 Counter
let counter: Vec<i32> = Counter::new(0, 10, 3).collect();
println!("Counter(0,10,3): {:?}", counter);

let counter2: Vec<i32> = Counter::new(1, 20, 5).collect();
println!("Counter(1,20,5): {:?}", counter2);

// 测试 top_n_scores
let mut students = vec![
("Alice", 85),
("Bob", 92),
("Charlie", 78),
("Diana", 95),
("Eve", 88),
];
let top2 = {
let mut tmp = students.clone();
tmp.sort_by_key(|(_, s)| std::cmp::Reverse(*s));
tmp.into_iter().take(2).map(|(n, _)| n).collect()
};
println!("前2名: {:?}", top2);

// 测试 group_by_length
let words = vec!["hi", "hello", "hey", "world", "ok", "rust"];
let grouped = group_by_length(&words);
let mut keys: Vec<usize> = grouped.keys().cloned().collect();
keys.sort_unstable();
for k in keys {
println!("长度{}: {:?}", k, grouped[&k]);
}

// 测试 running_average
let nums = vec![1.0, 3.0, 5.0, 7.0, 9.0];
let avgs = running_average(&nums);
println!("移动平均: {:?}", avgs);
}

修正说明:原来 top_n_scores 直接对切片调用 sort_by_key,sort会就地修改,而切片是不可变引用,编译报错。上面 main 里做了一份拷贝再排序;如果你希望函数内部完整实现版本(不污染外部),下面给 top_n_scores 的最终版:

fn top_n_scores<'a>(students: &'a [(&'a str, i32)], n: usize) -> Vec<&'a str> {
let mut v: Vec<_> = students.iter().collect();
v.sort_by_key(|(_, score)| std::cmp::Reverse(**score));
v.into_iter().take(n).map(|(name, _)| *name).collect()
}

把 top_n_scores 替换成这个版本,main就可以简化为:

let top2 = top_n_scores(&students, 2);

完整最终版(全部函数自包含,main干净)

use std::collections::HashMap;

// 自定义迭代器 Counter
struct Counter {
current: i32,
end: i32,
step: i32,
}

impl Counter {
fn new(start: i32, end: i32, step: i32) -> Self {
Counter {
current: start,
end,
step,
}
}
}

impl Iterator for Counter {
type Item = i32;

fn next(&mut self) -> Option<Self::Item> {
if self.current >= self.end {
return None;
}
let val = self.current;
self.current += self.step;
Some(val)
}
}

fn top_n_scores<'a>(students: &'a [(&'a str, i32)], n: usize) -> Vec<&'a str> {
let mut v: Vec<_> = students.iter().collect();
v.sort_by_key(|(_, score)| std::cmp::Reverse(**score));
v.into_iter().take(n).map(|(name, _)| *name).collect()
}

fn group_by_length<'a>(words: &'a [&'a str]) -> HashMap<usize, Vec<&'a str>> {
words.iter().fold(HashMap::new(), |mut map, w| {
map.entry(w.len()).or_default().push(*w);
map
})
}

fn running_average(numbers: &[f64]) -> Vec<f64> {
numbers
.iter()
.scan((0.0, 0), |(sum, count), &val| {
*sum += val;
*count += 1;
Some(*sum / (*count as f64))
})
.collect()
}

fn main() {
// 测试 Counter
let counter: Vec<i32> = Counter::new(0, 10, 3).collect();
println!("Counter(0,10,3): {:?}", counter);

let counter2: Vec<i32> = Counter::new(1, 20, 5).collect();
println!("Counter(1,20,5): {:?}", counter2);

// 测试 top_n_scores
let students = vec![
("Alice", 85),
("Bob", 92),
("Charlie", 78),
("Diana", 95),
("Eve", 88),
];
let top2 = top_n_scores(&students, 2);
println!("前2名: {:?}", top2);

// 测试 group_by_length
let words = vec!["hi", "hello", "hey", "world", "ok", "rust"];
let grouped = group_by_length(&words);
let mut keys: Vec<usize> = grouped.keys().cloned().collect();
keys.sort_unstable();
for k in keys {
println!("长度{}: {:?}", k, grouped[&k]);
}

// 测试 running_average
let nums = vec![1.0, 3.0, 5.0, 7.0, 9.0];
let avgs = running_average(&nums);
println!("移动平均: {:?}", avgs);
}

运行输出

plaintext

Counter(0,10,3): [0, 3, 6, 9] Counter(1,20,5): [1, 6, 11, 16] 前2名: [“Diana”, “Bob”] 长度2: [“hi”, “ok”] 长度3: [“hey”] 长度4: [“rust”] 长度5: [“hello”, “world”] 移动平均: [1.0, 2.0, 3.0, 4.0, 5.0]

知识点

1. 自定义迭代器 Counter 实现 Iterator ,Item = i32;next() 返回 Option,状态保存在结构体字段。调用 .collect() 自动把迭代器转为Vec。 2. top_n_scores 切片不可变,先把迭代器收集成临时Vec再排序, Reverse 实现降序;take(n)取前N条。 3. group_by_length fold 是万能的迭代器聚合;entry‑or_default 分组标准写法。 4. running_average(scan) scan 保存累加状态(sum,count),每一步产出一个值,非常适合前缀和、滚动平均场景。

赞(0)
未经允许不得转载:网硕互联帮助中心 » 【Rust入门知识点】第23课:迭代器 Iterators
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!