跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Rust算法

Rust 集合类型与迭代器详解

Rust 标准库中的五种集合类型(Vec、HashMap、HashSet、BTreeMap、BTreeSet)及其内存管理、时间复杂度与适用场景。详细讲解了迭代器的链式操作、适配器与消费者模式,以及惰性求值特性。通过自定义迭代器实现和单词统计、用户管理系统等实战案例,展示了如何高效处理复杂数据结构,并提供常见问题的解决方案。

时间旅人发布于 2026/2/4更新于 2026/10/254.1K 浏览
Rust 集合类型与迭代器详解

Rust 集合类型与迭代器详解

Rust 集合与迭代器结构图

学习目标与重点

学习目标
  1. 掌握标准库集合类型:理解 Vec、HashMap、HashSet、BTreeMap、BTreeSet 的定义、常用操作、内存管理与适用场景,学会根据业务需求选择合适的集合。
  2. 精通迭代器系统:熟练运用标准库迭代器的链式操作、适配器(filter、map、fold 等)、消费者(collect、sum 等),理解其惰性求值特性。
  3. 优化集合操作:深入了解不同集合的时间/空间复杂度,避免常见的性能陷阱(如 Vec 频繁扩容、HashMap 哈希碰撞)。
  4. 实现自定义迭代器:学习 Iterator trait 的完整实现流程,编写符合业务需求的自定义迭代器。
  5. 实战集合开发:结合真实场景编写单词统计、用户数据管理、任务调度系统,解决复杂的数据处理问题。
学习重点

💡 三大核心难点:

  1. Vec 的内存扩容策略:容量与长度的关系、预分配内存的优化技巧、插入删除操作的性能影响。
  2. 迭代器的链式调用与所有权转移:如何正确处理迭代过程中元素的所有权(如 into_iter、iter、iter_mut 的区别)。
  3. HashMap 的高级 API 与性能优化:Entry API 的使用(插入或更新、删除或获取)、负载因子的调整、哈希函数的自定义。

⚠️ 三大高频错误点:

  1. Vec 索引越界:访问不存在的索引导致程序 panic。
  2. 迭代器的双重可变引用:在 for 循环中直接修改集合导致编译错误(违反借用规则)。
  3. HashMap 键类型不符合要求:键类型未同时实现 Hash 和 Eq trait。

标准库集合类型详解

Rust 标准库提供了五种常用的集合类型,它们都存储在堆内存上,具有动态大小的特点。

2.1 动态数组 Vec

Vec 是 Rust 中最常用的线性集合类型,类似于 C++ 的 std::vector,支持快速的随机访问和尾部插入/删除操作。

2.1.1 基本操作
use std::vec::Vec;

fn main() {
    // 创建 Vec 的方法
    let mut vec1 = Vec::new(); // 创建空 Vec
    let vec2 = vec![1, , ]; 
      = ::(); 

    
    vec1.();
    vec1.();
    vec3.([, , ].()); 
    vec3.(, ); 

    
    vec3.(); 
    vec3.(); 

    
    (, vec2[]); 
    (, vec2.()); 
      = vec2.().(); 
    (, first_element);

    
      = [, , ];
    vec4[] = ; 
      (element) = vec4.() { 
        *element = ;
    }
    (, vec4); 

    
    ();
       &vec1 { 
        (, element);
    }
    ();
       & vec1 { 
        *element *= ;
        (, element);
    }
    ();
       vec1 { 
        (, element);
    }
    

    
      = ::();
    (, vec5.()); 
    (, vec5.()); 
       .. {
        vec5.(i);
        (, i + , vec5.(), vec5.());
    }
}
2
3
// 使用 vec!宏创建
let
mut
vec3
Vec
with_capacity
10
// 预分配 10 个元素的容量
// 插入元素
push
4
push
5
extend
6
7
8
iter
// 批量插入
insert
1
9
// 在索引 1 处插入 9
// 删除元素
pop
// 删除尾部元素(返回 Some(8))
remove
1
// 删除索引 1 处的元素(返回 9)
// 访问元素
println!
"vec2[0]: {}"
0
// 随机访问(panic 如果索引越界)
println!
"vec2.get(3): {:?}"
get
3
// 安全访问(返回 None)
let
first_element
first
expect
"vec2 是空的"
// 获取第一个元素(Option 类型)
println!
"vec2.first(): {}"
// 修改元素
let
mut
vec4
vec!
10
20
30
0
100
// 直接修改
if
let
Some
get_mut
1
// 安全修改
200
println!
"vec4: {:?}"
// [100, 200, 30]
// 遍历 Vec
println!
"vec1 遍历:"
for
element
in
// 不可变引用遍历
println!
"{}"
println!
"vec1 可变引用遍历并修改:"
for
element
in
mut
// 可变引用遍历
2
println!
"{}"
println!
"vec1 消费遍历:"
for
element
in
// 消费遍历(转移所有权)
println!
"{}"
// println!("vec1: {:?}", vec1); // 编译错误:vec1 的所有权已转移
// Vec 的容量与长度
let
mut
vec5
Vec
with_capacity
5
println!
"vec5 初始容量:{}"
capacity
// 5
println!
"vec5 初始长度:{}"
len
// 0
for
i
in
0
10
push
println!
"插入第{}个元素后,容量:{}, 长度:{}"
1
capacity
len
2.1.2 高级用法

✅ 预分配内存优化:使用 Vec::with_capacity 预分配足够的容量,避免频繁扩容导致的内存拷贝。 ✅ 容量调整:使用 shrink_to_fit 将容量缩小到与长度相同。 ✅ 切片转换:使用 as_slice 或 &vec[..] 将 Vec 转换为切片(Slice),使用 from_slice 将切片转换为 Vec。 ✅ 批量操作:使用 extend、append、retain 进行批量插入、合并、过滤操作。

fn main() {
    // 预分配内存优化
    let mut vec1 = Vec::with_capacity(1000);
    for i in 0..1000 {
        vec1.push(i);
    }
    println!("vec1 预分配后容量:{}", vec1.capacity()); // 1000

    // 容量调整
    vec1.truncate(500); // 截断到长度 500
    println!("vec1 截断后长度:{}", vec1.len()); // 500
    println!("vec1 截断后容量:{}", vec1.capacity()); // 1000
    vec1.shrink_to_fit(); // 缩小容量到 500
    println!("vec1 缩小后容量:{}", vec1.capacity()); // 500

    // 切片转换
    let vec2 = vec![1, 2, 3];
    let slice = vec2.as_slice();
    println!("vec2 转换为切片:{:?}", slice);
    let vec3 = Vec::from(slice);
    println!("切片转换为 Vec: {:?}", vec3);

    // 批量操作
    let mut vec4 = vec![1, 3, 5, 7, 9];
    vec4.extend([11, 13].iter()); // 批量插入
    println!("vec4 批量插入后:{:?}", vec4);
    let mut vec5 = vec![2, 4, 6];
    vec4.append(&mut vec5); // 合并 vec5 到 vec4(vec5 变为空)
    println!("vec4 合并 vec5 后:{:?}", vec4);
    println!("vec5 合并后:{:?}", vec5);
    vec4.retain(|x| x % 2 == 1); // 保留奇数
    println!("vec4 保留奇数后:{:?}", vec4);
}
2.1.3 适用场景与时间复杂度

✅ 适用场景:需要频繁随机访问或尾部插入/删除的场景,如列表、数组缓冲区。 ✅ 时间复杂度:

  • 随机访问:O(1)
  • 尾部插入/删除:O(1)(amortized,平均)
  • 中间插入/删除:O(n)
  • 扩容:O(n)(当容量不足时,重新分配 2 倍内存并拷贝所有元素)
2.2 哈希表 HashMap<K, V>

HashMap<K, V> 是 Rust 中最常用的键值对集合类型,类似于 C++ 的 std::unordered_map,支持快速的插入、删除、查找操作(平均 O(1))。

2.2.1 基本操作
use std::collections::HashMap;

fn main() {
    // 创建 HashMap 的方法
    let mut map1 = HashMap::new(); // 创建空 HashMap
    let map2 = HashMap::from([
        ("key1", "value1"),
        ("key2", "value2"),
        ("key3", "value3"),
    ]); // 使用 from 方法创建
    let mut map3 = HashMap::with_capacity(10); // 预分配 10 个桶的容量

    // 插入元素
    map1.insert("key1", 10);
    map1.insert("key2", 20);
    map3.extend([("key3", 30), ("key4", 40)].iter()); // 批量插入

    // 删除元素
    map1.remove("key1"); // 删除键为 key1 的元素(返回 Some(10))
    map1.clear(); // 清空所有元素

    // 访问元素
    let value1 = map2.get("key1").expect("key1 不存在"); // 安全访问(返回 Option 类型)
    println!("map2.get(\"key1\"): {}", value1);

    // 修改元素
    let mut map4 = HashMap::from([("name", "张三"), ("age", "25")]);
    map4.insert("age", "26"); // 直接覆盖
    if let Some(value) = map4.get_mut("name") { // 安全修改
        *value = "李四";
    }
    println!("map4 修改后:{:?}", map4);

    // 遍历 HashMap
    println!("map2 遍历键:");
    for key in map2.keys() {
        println!("{}", key);
    }
    println!("map2 遍历值:");
    for value in map2.values() {
        println!("{}", value);
    }
    println!("map2 遍历键值对:");
    for (key, value) in &map2 { // 不可变引用遍历
        println!("{}: {}", key, value);
    }
    println!("map4 遍历键值对并修改:");
    for (key, value) in map4.iter_mut() { // 可变引用遍历
        if key == &"age" {
            *value = "27";
        }
        println!("{}: {}", key, value);
    }

    // HashMap 的容量与负载因子
    let mut map5 = HashMap::with_capacity(10);
    for i in 0..8 {
        map5.insert(i, i * 2);
        println!("插入第{}个元素后,容量:{}, 长度:{}, 负载因子:{}", i + 1, map5.capacity(), map5.len(), map5.len() as f64 / map5.capacity() as f64);
    }
}
2.2.2 高级用法:Entry API

Entry API 是 HashMap 最强大的功能之一,它允许我们原子性地执行'插入或更新'、'删除或获取'等操作,避免了多次查找导致的性能损耗。

use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();
    scores.insert("张三", 80);

    // 插入或更新:如果键存在,就执行更新操作;如果不存在,就插入默认值
    let zhang_san_score = scores.entry("张三").or_insert(0);
    *zhang_san_score += 10;
    println!("张三的分数:{}", zhang_san_score);

    let li_si_score = scores.entry("李四").or_insert(0);
    *li_si_score += 90;
    println!("李四的分数:{}", li_si_score);

    let wang_wu_score = scores.entry("王五").or_insert_with(|| {
        println!("王五的分数不存在,插入默认值 85");
        85
    });
    println!("王五的分数:{}", wang_wu_score);

    // 删除或获取:如果键存在,就获取并删除值;如果不存在,就返回默认值
    let removed_score = scores.remove_entry("张三").map(|(_, v)| v).unwrap_or(0);
    println!("删除张三的分数:{}", removed_score);

    // 批量更新:统计单词出现的次数
    let text = "Hello, Rust! This is a test. Hello, world!";
    let mut word_count = HashMap::new();
    for word in text.split_whitespace() {
        let clean_word = word.chars().filter(|c| c.is_alphanumeric()).collect::<String>().to_lowercase();
        if !clean_word.is_empty() {
            word_count.entry(clean_word).and_modify(|count| *count += 1).or_insert(1);
        }
    }
    println!("单词统计:{:?}", word_count);
}
2.2.3 适用场景与时间复杂度

✅ 适用场景:需要频繁插入、删除、查找键值对的场景,如用户数据管理、缓存系统、单词统计。 ✅ 时间复杂度:

  • 插入/删除/查找:平均 O(1),最坏 O(n)(哈希碰撞严重)
  • 遍历:O(n)

⚠️ 性能优化技巧:

  1. 预分配容量:使用 HashMap::with_capacity 预分配足够的桶容量,避免频繁扩容。
  2. 调整负载因子:默认负载因子为 0.75,可以通过 HashMap::with_hasher 或 HashMap::with_capacity_and_hasher 调整,但会影响空间复杂度。
  3. 自定义哈希函数:使用 std::collections::hash_map::DefaultHasher 以外的哈希函数,如 SipHash、FnvHash(需要第三方库)。
2.3 哈希集合 HashSet

HashSet 是 Rust 中最常用的集合类型,类似于 C++ 的 std::unordered_set,它存储不重复的元素,支持快速的插入、删除、查找操作(平均 O(1))。

2.3.1 基本操作
use std::collections::HashSet;

fn main() {
    // 创建 HashSet 的方法
    let mut set1 = HashSet::new(); // 创建空 HashSet
    let set2 = HashSet::from([1, 2, 3]); // 使用 from 方法创建
    let mut set3 = HashSet::with_capacity(10); // 预分配 10 个桶的容量

    // 插入元素
    set1.insert(4);
    set1.insert(5);
    set3.extend([6, 7, 8].iter()); // 批量插入

    // 删除元素
    set1.remove(&4); // 删除值为 4 的元素(返回 true)
    set1.clear(); // 清空所有元素

    // 查找元素
    let contains_2 = set2.contains(&2); // 判断是否包含值为 2 的元素
    println!("set2.contains(&2): {}", contains_2);

    // 遍历 HashSet
    println!("set2 遍历:");
    for element in &set2 {
        println!("{}", element);
    }

    // 集合运算
    let set_a = HashSet::from([1, 2, 3, 4]);
    let set_b = HashSet::from([3, 4, 5, 6]);
    println!("set_a: {:?}", set_a);
    println!("set_b: {:?}", set_b);
    println!("交集:{:?}", set_a.intersection(&set_b).collect::<Vec<_>>());
    println!("并集:{:?}", set_a.union(&set_b).collect::<Vec<_>>());
    println!("差集:{:?}", set_a.difference(&set_b).collect::<Vec<_>>());
    println!("对称差集:{:?}", set_a.symmetric_difference(&set_b).collect::<Vec<_>>());

    // 子集判断
    let set_c = HashSet::from([3, 4]);
    let is_subset = set_c.is_subset(&set_a);
    println!("set_c 是 set_a 的子集:{}", is_subset);
}
2.3.2 适用场景与时间复杂度

✅ 适用场景:需要存储不重复元素且频繁进行集合运算的场景,如标签管理、去重操作、权限验证。 ✅ 时间复杂度:与 HashMap<K, V> 相同,因为 HashSet 内部是 HashMap<T, ()> 的封装。

2.4 有序字典 BTreeMap<K, V>

BTreeMap<K, V> 是 Rust 中最常用的有序键值对集合类型,类似于 C++ 的 std::map,它存储按键排序的键值对,支持快速的插入、删除、查找操作(O(log n))。

2.4.1 基本操作
use std::collections::BTreeMap;

fn main() {
    // 创建 BTreeMap 的方法
    let mut map1 = BTreeMap::new(); // 创建空 BTreeMap
    let map2 = BTreeMap::from([
        ("key1", "value1"),
        ("key2", "value2"),
        ("key3", "value3"),
    ]); // 使用 from 方法创建

    // 插入元素
    map1.insert("key1", 10);
    map1.insert("key2", 20);

    // 删除元素
    map1.remove("key1"); // 删除键为 key1 的元素(返回 Some(10))
    map1.clear(); // 清空所有元素

    // 访问元素
    let value1 = map2.get("key1").expect("key1 不存在"); // 安全访问(返回 Option 类型)
    println!("map2.get(\"key1\"): {}", value1);

    // 修改元素
    let mut map4 = BTreeMap::from([("name", "张三"), ("age", "25")]);
    map4.insert("age", "26"); // 直接覆盖
    if let Some(value) = map4.get_mut("name") { // 安全修改
        *value = "李四";
    }
    println!("map4 修改后:{:?}", map4);

    // 遍历 BTreeMap
    println!("map2 遍历键(有序):");
    for key in map2.keys() {
        println!("{}", key);
    }
    println!("map2 遍历值(有序):");
    for value in map2.values() {
        println!("{}", value);
    }
    println!("map2 遍历键值对(有序):");
    for (key, value) in &map2 { // 不可变引用遍历
        println!("{}: {}", key, value);
    }

    // 范围查询
    let mut map5 = BTreeMap::from([(1, "a"), (2, "b"), (3, "c"), (4, "d"), (5, "e")]);
    println!("范围查询 1..=3: {:?}", map5.range(1..=3).collect::<Vec<_>>());
    println!("范围查询..3: {:?}", map5.range(..3).collect::<Vec<_>>());
    println!("范围查询 3..: {:?}", map5.range(3..).collect::<Vec<_>>());
}
2.4.2 适用场景与时间复杂度

✅ 适用场景:需要存储有序键值对且频繁进行范围查询的场景,如任务调度、排行榜、数据库索引。 ✅ 时间复杂度:

  • 插入/删除/查找:O(log n)
  • 范围查询:O(log n + k)(k 是查询结果的数量)
  • 遍历:O(n)
2.5 有序集合 BTreeSet

BTreeSet 是 Rust 中最常用的有序集合类型,类似于 C++ 的 std::set,它存储按值排序的不重复元素,支持快速的插入、删除、查找操作(O(log n))。

2.5.1 基本操作
use std::collections::BTreeSet;

fn main() {
    // 创建 BTreeSet 的方法
    let mut set1 = BTreeSet::new(); // 创建空 BTreeSet
    let set2 = BTreeSet::from([1, 2, 3]); // 使用 from 方法创建

    // 插入元素
    set1.insert(4);
    set1.insert(5);

    // 删除元素
    set1.remove(&4); // 删除值为 4 的元素(返回 true)
    set1.clear(); // 清空所有元素

    // 查找元素
    let contains_2 = set2.contains(&2); // 判断是否包含值为 2 的元素
    println!("set2.contains(&2): {}", contains_2);

    // 遍历 BTreeSet
    println!("set2 遍历(有序):");
    for element in &set2 {
        println!("{}", element);
    }

    // 集合运算
    let set_a = BTreeSet::from([1, 2, 3, 4]);
    let set_b = BTreeSet::from([3, 4, 5, 6]);
    println!("set_a: {:?}", set_a);
    println!("set_b: {:?}", set_b);
    println!("交集:{:?}", set_a.intersection(&set_b).collect::<Vec<_>>());
    println!("并集:{:?}", set_a.union(&set_b).collect::<Vec<_>>());
    println!("差集:{:?}", set_a.difference(&set_b).collect::<Vec<_>>());
    println!("对称差集:{:?}", set_a.symmetric_difference(&set_b).collect::<Vec<_>>());

    // 范围查询
    let mut set_c = BTreeSet::from([10, 20, 30, 40, 50]);
    println!("范围查询 20..=40: {:?}", set_c.range(20..=40).collect::<Vec<_>>());
    println!("范围查询..30: {:?}", set_c.range(..30).collect::<Vec<_>>());
    println!("范围查询 30..: {:?}", set_c.range(30..).collect::<Vec<_>>());
}
2.5.2 适用场景与时间复杂度

✅ 适用场景:需要存储有序不重复元素且频繁进行范围查询的场景,如任务调度、排序去重、权限验证。 ✅ 时间复杂度:与 BTreeMap<K, V> 相同,因为 BTreeSet 内部是 BTreeMap<T, ()> 的封装。

迭代器系统详解

迭代器系统是 Rust 中最强大的功能之一,它允许我们以统一的方式遍历各种集合类型,并且支持链式操作和惰性求值,提高了代码的可读性和可维护性。

3.1 迭代器的定义与基本操作

迭代器是实现了 Iterator trait 的类型,它有一个 next 方法,每次调用返回一个 OptionSelf::Item 类型的值,当迭代结束时返回 None。

use std::collections::HashMap;

fn main() {
    // Vec 的迭代器
    let vec = vec![1, 2, 3];
    let mut vec_iter = vec.iter(); // 不可变引用迭代器
    println!("vec.iter().next(): {:?}", vec_iter.next()); // Some(1)
    println!("vec.iter().next(): {:?}", vec_iter.next()); // Some(2)
    println!("vec.iter().next(): {:?}", vec_iter.next()); // Some(3)
    println!("vec.iter().next(): {:?}", vec_iter.next()); // None

    let mut vec_iter_mut = vec.iter_mut(); // 可变引用迭代器
    while let Some(element) = vec_iter_mut.next() {
        *element *= 2;
    }
    println!("vec: {:?}", vec); // [2, 4, 6]

    let mut vec_into_iter = vec.into_iter(); // 消费迭代器(转移所有权)
    while let Some(element) = vec_into_iter.next() {
        println!("{}", element);
    }
    // println!("vec: {:?}", vec); // 编译错误:vec 的所有权已转移

    // HashMap 的迭代器
    let map = HashMap::from([("key1", "value1"), ("key2", "value2")]);
    let mut map_iter = map.iter();
    println!("map.iter().next(): {:?}", map_iter.next()); // Some(("key1", "value1"))

    // 范围的迭代器
    let range = 1..=5;
    let mut range_iter = range.iter();
    println!("range.iter().next(): {:?}", range_iter.next()); // Some(1)
}
3.2 迭代器的适配器与消费者

迭代器系统提供了两种类型的方法:

  1. 适配器(Adapter):接受一个迭代器作为输入,返回一个新的迭代器(如 filter、map、take)。
  2. 消费者(Consumer):接受一个迭代器作为输入,返回一个非迭代器类型的值(如 collect、sum、fold)。
3.2.1 适配器示例
fn main() {
    let vec = vec![1, 2, 3, 4, 5];

    // filter:过滤满足条件的元素
    let filtered_vec: Vec<_> = vec.iter()
        .filter(|&&x| x % 2 == 1) // 保留奇数
        .map(|&x| x * 2) // 乘以 2
        .collect();
    println!("filtered_vec: {:?}", filtered_vec); // [2, 6, 10]

    // take:只取前 3 个元素
    let taken_vec: Vec<_> = vec.iter().take(3).collect();
    println!("taken_vec: {:?}", taken_vec); // [1, 2, 3]

    // skip:跳过前 2 个元素
    let skipped_vec: Vec<_> = vec.iter().skip(2).collect();
    println!("skipped_vec: {:?}", skipped_vec); // [3, 4, 5]

    // chain:连接两个迭代器
    let vec1 = vec![1, 2];
    let vec2 = vec![3, 4];
    let chained_vec: Vec<_> = vec1.iter().chain(vec2.iter()).collect();
    println!("chained_vec: {:?}", chained_vec); // [1, 2, 3, 4]

    // zip:将两个迭代器合并成一个元组迭代器
    let vec3 = vec![1, 2, 3];
    let vec4 = vec!["a", "b", "c"];
    let zipped_vec: Vec<_> = vec3.iter().zip(vec4.iter()).collect();
    println!("zipped_vec: {:?}", zipped_vec); // [(1, "a"), (2, "b"), (3, "c")]
}
3.2.2 消费者示例
fn main() {
    let vec = vec![1, 2, 3, 4, 5];

    // collect:将迭代器转换为集合类型(如 Vec、HashMap、HashSet)
    let vec_collected: Vec<_> = vec.iter().collect();
    println!("vec_collected: {:?}", vec_collected); // [1, 2, 3, 4, 5]

    // sum:计算所有元素的和
    let sum = vec.iter().sum::<i32>();
    println!("sum: {}", sum); // 15

    // product:计算所有元素的积
    let product = vec.iter().product::<i32>();
    println!("product: {}", product); // 120

    // fold:累加器操作
    let fold_result = vec.iter().fold(0, |acc, &x| acc + x * 2);
    println!("fold_result: {}", fold_result); // 0 + 2 + 4 + 6 + 8 + 10 = 30

    // any:判断是否有满足条件的元素
    let has_even = vec.iter().any(|&&x| x % 2 == 0);
    println!("has_even: {}", has_even); // true

    // all:判断是否所有元素都满足条件
    let all_even = vec.iter().all(|&&x| x % 2 == 0);
    println!("all_even: {}", all_even); // false
}
3.3 惰性求值特性

Rust 的迭代器是惰性求值的,也就是说,迭代器的适配器操作只有在调用消费者方法时才会真正执行。这种特性可以提高代码的性能,避免不必要的计算。

fn main() {
    // 这个操作不会真正执行,因为没有调用消费者方法
    let vec = vec![1, 2, 3];
    let _filtered_iter = vec.iter().filter(|&&x| {
        println!("过滤操作:{}", x); // 不会输出
        x % 2 == 1
    });

    // 只有在调用 collect 方法时才会执行
    let filtered_vec: Vec<_> = vec.iter().filter(|&&x| {
        println!("过滤操作:{}", x);
        x % 2 == 1
    }).collect();
    println!("filtered_vec: {:?}", filtered_vec);
    // 输出:
    // 过滤操作:1
    // 过滤操作:2
    // 过滤操作:3
    // filtered_vec: [1, 3]
}
3.4 实现自定义迭代器

我们可以通过实现 Iterator trait 来编写符合自己业务需求的自定义迭代器,只需要实现一个 next 方法即可。

// 定义一个自定义的 RangeIter 类型
struct RangeIter {
    current: i32,
    end: i32,
}

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

// 实现 Iterator trait
impl Iterator for RangeIter {
    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
        }
    }
}

// 定义一个自定义的 EvenRangeIter 类型,继承自 RangeIter,只返回偶数
struct EvenRangeIter {
    iter: RangeIter,
}

impl EvenRangeIter {
    fn new(start: i32, end: i32) -> Self {
        EvenRangeIter { iter: RangeIter::new(start, end) }
    }
}

// 实现 Iterator trait
impl Iterator for EvenRangeIter {
    type Item = i32;
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(x) = self.iter.next() {
            if x % 2 == 0 {
                return Some(x);
            }
        }
        None
    }
}

fn main() {
    // 测试 RangeIter
    println!("RangeIter 0..5:");
    for x in RangeIter::new(0, 5) {
        println!("{}", x);
    }
    println!("----------");

    // 测试 EvenRangeIter
    println!("EvenRangeIter 0..5:");
    for x in EvenRangeIter::new(0, 5) {
        println!("{}", x);
    }

    // 使用适配器操作自定义迭代器
    let even_squared: Vec<_> = EvenRangeIter::new(0, 10).map(|x| x * x).collect();
    println!("EvenRangeIter 0..10 平方:{:?}", even_squared);
}

真实案例应用

4.1 案例 1:实现高效的单词统计系统

💡 场景分析:需要编写一个高效的单词统计系统,支持统计文本中单词出现的次数,过滤特殊字符,不区分大小写。

use std::collections::HashMap;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

// 定义单词统计函数
fn count_words_in_file(file_path: PathBuf) -> Result<HashMap<String, u32>, Box<dyn std::error::Error>> {
    let file = File::open(file_path)?;
    let reader = BufReader::new(file);
    let mut word_count = HashMap::new();
    for line_result in reader.lines() {
        let line = line_result?;
        let cleaned_line = line.chars().map(|c| if c.is_alphanumeric() || c.is_whitespace() { c } else { ' ' }).collect::<String>();
        for word in cleaned_line.split_whitespace() {
            let lower_word = word.to_lowercase();
            word_count.entry(lower_word).and_modify(|count| *count += 1).or_insert(1);
        }
    }
    Ok(word_count)
}

// 排序单词统计结果(按出现次数降序)
fn sort_word_count(word_count: HashMap<String, u32>) -> Vec<(String, u32)> {
    let mut sorted_word_count: Vec<_> = word_count.into_iter().collect();
    sorted_word_count.sort_by(|a, b| b.1.cmp(&a.1));
    sorted_word_count
}

fn main() {
    // 读取命令行参数
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 2 {
        println!("Usage: cargo run <file_path>");
        return;
    }
    let file_path = PathBuf::from(&args[1]);

    // 统计单词
    let word_count = match count_words_in_file(file_path) {
        Ok(count) => count,
        Err(e) => {
            println!("错误:{}", e);
            return;
        }
    };

    // 排序结果
    let sorted_word_count = sort_word_count(word_count);

    // 输出结果
    println!("单词统计结果(按出现次数降序):");
    println!("----------");
    println!("{:<20} {}", "单词", "出现次数");
    println!("----------");
    for (word, count) in sorted_word_count {
        println!("{:<20} {}", word, count);
    }
}
4.2 案例 2:实现用户数据管理系统

💡 场景分析:需要编写一个简单的用户数据管理系统,支持添加用户、删除用户、查询用户、修改用户信息,使用 BTreeMap 存储用户数据,以便按用户名排序。

use std::collections::BTreeMap;
use std::io::{stdin, stdout, Write};

// 定义用户结构体
#[derive(Debug)]
struct User {
    name: String,
    email: String,
    age: u8,
}

impl User {
    fn new(name: String, email: String, age: u8) -> Self {
        User { name, email, age }
    }

    fn print_info(&self) {
        println!("姓名:{}", self.name);
        println!("邮箱:{}", self.email);
        println!("年龄:{}", self.age);
    }
}

// 定义用户数据管理系统
struct UserManager {
    users: BTreeMap<String, User>,
}

impl UserManager {
    fn new() -> Self {
        UserManager { users: BTreeMap::new() }
    }

    fn add_user(&mut self, user: User) {
        self.users.insert(user.name.clone(), user);
        println!("用户添加成功");
    }

    fn delete_user(&mut self, name: &str) {
        if self.users.remove(name).is_some() {
            println!("用户删除成功");
        } else {
            println!("用户不存在");
        }
    }

    fn find_user(&self, name: &str) -> Option<&User> {
        self.users.get(name)
    }

    fn modify_user(&mut self, name: &str, email: Option<String>, age: Option<u8>) {
        if let Some(user) = self.users.get_mut(name) {
            if let Some(email) = email {
                user.email = email;
            }
            if let Some(age) = age {
                user.age = age;
            }
            println!("用户信息修改成功");
        } else {
            println!("用户不存在");
        }
    }

    fn list_users(&self) {
        if self.users.is_empty() {
            println!("用户列表是空的");
            return;
        }
        println!("用户列表(按用户名排序):");
        println!("----------");
        for (_, user) in &self.users {
            user.print_info();
            println!("----------");
        }
    }
}

// 获取用户输入的辅助函数
fn get_input(prompt: &str) -> String {
    print!("{}", prompt);
    stdout().flush().expect("刷新缓冲区失败");
    let mut input = String::new();
    stdin().read_line(&mut input).expect("读取输入失败");
    input.trim().to_string()
}

fn main() {
    let mut user_manager = UserManager::new();
    loop {
        println!("用户数据管理系统");
        println!("----------------");
        println!("1. 添加用户");
        println!("2. 删除用户");
        println!("3. 查询用户");
        println!("4. 修改用户信息");
        println!("5. 列出所有用户");
        println!("6. 退出");
        println!("----------------");
        println!("请输入操作编号:");
        let choice = get_input("");
        match choice.as_str() {
            "1" => {
                println!("请输入用户信息:");
                let name = get_input("姓名:");
                let email = get_input("邮箱:");
                let age_str = get_input("年龄:");
                if let Ok(age) = age_str.parse::<u8>() {
                    let user = User::new(name, email, age);
                    user_manager.add_user(user);
                } else {
                    println!("年龄无效,请输入整数");
                }
            }
            "2" => {
                let name = get_input("请输入要删除的用户姓名:");
                user_manager.delete_user(&name);
            }
            "3" => {
                let name = get_input("请输入要查询的用户姓名:");
                if let Some(user) = user_manager.find_user(&name) {
                    println!("用户信息:");
                    user.print_info();
                } else {
                    println!("用户不存在");
                }
            }
            "4" => {
                let name = get_input("请输入要修改的用户姓名:");
                let email = get_input("请输入新的邮箱(留空表示不修改):");
                let age_str = get_input("请输入新的年龄(留空表示不修改):");
                let email = if email.is_empty() {
                    None
                } else {
                    Some(email)
                };
                let age = if age_str.is_empty() {
                    None
                } else {
                    age_str.parse::<u8>().ok()
                };
                user_manager.modify_user(&name, email, age);
            }
            "5" => user_manager.list_users(),
            "6" => {
                println!("用户数据管理系统结束");
                break;
            }
            _ => println!("无效的操作编号"),
        }
        println!();
    }
}

常见问题与解决方案

5.1 Vec 的索引越界

问题现象:访问不存在的索引导致程序 panic。

解决方案:

  1. 使用 get 或 get_mut 方法安全访问,返回 Option 类型。
  2. 在访问前检查索引是否在有效范围内。
  3. 使用迭代器遍历 Vec,避免直接访问索引。
5.2 迭代器的双重可变引用

问题现象:在 for 循环中直接修改集合导致编译错误(违反借用规则)。

解决方案:

  1. 使用 iter_mut 方法获取可变引用迭代器。
  2. 如果需要在遍历过程中删除元素,可以使用 retain 方法。
  3. 如果需要在遍历过程中插入元素,可以使用 Vec::insert 方法,但会影响性能(O(n) 时间复杂度)。
5.3 HashMap 的键类型不符合要求

问题现象:键类型未同时实现 Hash 和 Eq trait。

解决方案:

  1. 检查键类型是否实现了 Hash 和 Eq trait。
  2. 如果使用自定义类型作为键,需要手动实现 Hash 和 Eq trait。
  3. 可以使用 derive 宏自动实现 Hash 和 Eq trait(如 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)])。

总结与展望

6.1 总结

✅ 掌握了标准库集合类型:理解了 Vec、HashMap、HashSet、BTreeMap、BTreeSet 的定义、常用操作、适用场景与时间复杂度。 ✅ 精通了迭代器系统:熟练运用了标准库迭代器的链式操作、适配器、消费者,理解了其惰性求值特性。 ✅ 优化了集合操作:学习了 Vec 的预分配内存优化、HashMap 的 Entry API 与性能优化技巧。 ✅ 实现了自定义迭代器:深入学习了 Iterator trait 的完整实现流程,编写了符合自己业务需求的自定义迭代器。 ✅ 实战集合开发:结合真实场景编写了两个实用的代码案例:高效的单词统计系统和用户数据管理系统。

6.2 展望

下一篇文章,我们将深入学习 Rust 的文件操作与网络编程,包括文件的读写、目录的操作、网络通信(TCP、UDP、HTTP),通过这些知识我们将能够编写更复杂的应用程序,如 Web 服务器、客户端、数据处理工具。

目录

  1. Rust 集合类型与迭代器详解
  2. 学习目标与重点
  3. 学习目标
  4. 学习重点
  5. 标准库集合类型详解
  6. 2.1 动态数组 Vec
  7. 2.1.1 基本操作
  8. 2.1.2 高级用法
  9. 2.1.3 适用场景与时间复杂度
  10. 2.2 哈希表 HashMap<K, V>
  11. 2.2.1 基本操作
  12. 2.2.2 高级用法:Entry API
  13. 2.2.3 适用场景与时间复杂度
  14. 2.3 哈希集合 HashSet
  15. 2.3.1 基本操作
  16. 2.3.2 适用场景与时间复杂度
  17. 2.4 有序字典 BTreeMap<K, V>
  18. 2.4.1 基本操作
  19. 2.4.2 适用场景与时间复杂度
  20. 2.5 有序集合 BTreeSet
  21. 2.5.1 基本操作
  22. 2.5.2 适用场景与时间复杂度
  23. 迭代器系统详解
  24. 3.1 迭代器的定义与基本操作
  25. 3.2 迭代器的适配器与消费者
  26. 3.2.1 适配器示例
  27. 3.2.2 消费者示例
  28. 3.3 惰性求值特性
  29. 3.4 实现自定义迭代器
  30. 真实案例应用
  31. 4.1 案例 1:实现高效的单词统计系统
  32. 4.2 案例 2:实现用户数据管理系统
  33. 常见问题与解决方案
  34. 5.1 Vec 的索引越界
  35. 5.2 迭代器的双重可变引用
  36. 5.3 HashMap 的键类型不符合要求
  37. 总结与展望
  38. 6.1 总结
  39. 6.2 展望

更多推荐文章

查看全部
  • C++ 分布式 AI 调度平台构建与架构设计实践
  • Qwen-Image 与 Midjourney V6 实测:中文理解与细节还原能力对比
  • ORB-SLAM3 开源视觉与视觉惯性 SLAM 库详解
  • Python 字符串格式化详解:%、format 与 f-string
  • AIGC 个性化与定制化内容生成:技术原理与应用实践
  • AI 可能引发大规模生物风险,专家呼吁建立跨学科团队
  • 从零构建大模型:核心原理与实战指南
  • 从医疗行业转型人工智能项目管理:求职实战经验
  • OpenClaw 多飞书机器人与多 Agent 团队实战复盘
  • OpenFPGA FPGA IP 核生成技术指南
  • ComfyUI Windows 本地部署系统环境配置指南(含 Python PyTorch CUDA)
  • 零成本实现 Web 实时推送:轻量级 SSE 方案解析
  • 前缀和算法应用详解
  • ComfyUI 自动翻译插件 alekpet 使用指南
  • Spring AOP 核心原理与实战指南
  • Java ArrayList 核心解析:原理、用法与扩容机制
  • Web3 前端安全:钱包连接风险与防护指南
  • 手势控制电脑方案分析与 Python 实现示例
  • 数据结构:树、森林与二叉树的转换详解
  • 数据结构 - 多维数组的超平面视角:从索引到地址的映射

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online