Vec:Rust 的动态数组
Vec<T> 是 Rust 最常用的集合,类似 JavaScript 的 Array,但有严格的类型约束和所有权语义。
对比:
JS
JavaScriptconst nums = [1, 2, 3];
nums.push(4);
const doubled = nums.map(x => x * 2);
const evens = doubled.filter(x => x % 2 === 0);Rs
Rustlet mut nums = vec![1, 2, 3];
nums.push(4);
let result: Vec<i32> = nums
.iter()
.map(|x| x * 2)
.filter(|x| x % 2 == 0)
.collect();Rust 迭代器是惰性求值的——.map() 和 .filter() 不立即执行,直到 .collect() 驱动消费。这让链式操作几乎无额外开销,等价于手写循环。
Vec 常用操作
let mut v: Vec<String> = Vec::new();
v.push(String::from("hello"));
v.push(String::from("world"));
// 索引访问(可能 panic)
let first = &v[0];
// 安全访问
if let Some(val) = v.get(0) {
println!("{}", val);
}
// 遍历
for item in &v {
println!("{}", item);
}HashMap:键值存储
use std::collections::HashMap;
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert(String::from("Alice"), 100);
scores.insert(String::from("Bob"), 85);
// entry API:不存在才插入
scores.entry(String::from("Charlie")).or_insert(70);
// 统计词频(经典用法)
let text = "hello world hello rust";
let mut word_count: HashMap<&str, i32> = HashMap::new();
for word in text.split_whitespace() {
let count = word_count.entry(word).or_insert(0);
*count += 1;
}entry().or_insert() 返回值的可变引用,*count += 1 直接修改 HashMap 内部的值,无需二次查找——这是 Rust 常见的惯用法。
闭包:捕获环境的匿名函数
对比:
JS
JavaScriptconst threshold = 50;
const passing = scores.filter(s => s > threshold);
const grader = score => score >= 90 ? 'A' : 'B';Rs
Rustlet threshold = 50;
let passing: Vec<i32> = scores
.iter()
.filter(|&&s| s > threshold) // 捕获 threshold
.copied()
.collect();
let grader = |score: i32| if score >= 90 { 'A' } else { 'B' };Rust 闭包有三种捕获方式,编译器自动推断:
| Trait | 捕获方式 | 类比 |
|---|---|---|
FnOnce | 消耗捕获的值(move) | 只能调用一次 |
FnMut | 可变借用捕获的值 | 可多次调用,可修改 |
Fn | 不可变借用捕获的值 | 可多次调用,只读 |
迭代器:零成本的链式操作
迭代器适配器(adapters)不执行计算,消费适配器(consumers)触发计算:
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 适配器:map、filter、take、skip、flat_map、zip...
// 消费器:collect、sum、count、fold、any、all、find...
let sum_of_even_squares: i32 = numbers
.iter()
.filter(|&&n| n % 2 == 0) // 适配器
.map(|&n| n * n) // 适配器
.sum(); // 消费器
// 等价于:
let mut sum = 0;
for n in &numbers {
if n % 2 == 0 { sum += n * n; }
}
// 编译后性能相同Iterator::collect() 可以收集到任何实现了 FromIterator 的类型:Vec<T>、HashMap<K,V>、String、HashSet<T> 等。类型注解或 turbofish 语法 (::<Vec<_>>) 告诉编译器收集到哪种类型。
自定义迭代器
struct Counter {
count: u32,
max: u32,
}
impl Counter {
fn new(max: u32) -> Counter {
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
}
}
}
// 自动获得所有迭代器方法
let sum: u32 = Counter::new(5).zip(Counter::new(5).skip(1))
.map(|(a, b)| a * b)
.filter(|x| x % 3 == 0)
.sum();String vs &str
// String:堆分配,拥有所有权,可修改
let mut owned: String = String::from("hello");
owned.push_str(", world");
// &str:字符串切片,借用,不可修改
let borrowed: &str = "hello"; // 字符串字面量,'static 生命周期
let slice: &str = &owned[0..5]; // 借用 String 的一部分
// 函数参数推荐用 &str,更灵活
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
// greet("Alice") -- &str 直接用
// greet(&my_string) -- String 自动解引用为 &str集合与迭代器实战演示
从零构建日志分析器:读取日志文件、用 HashMap 统计错误类型、用迭代器链计算各级别日志占比
视频即将上线
实战项目
日志分析器
初级
读取结构化日志文件,用 HashMap 统计各错误级别(ERROR/WARN/INFO)的出现频次和占比,用迭代器链计算 Top 5 高频错误消息,最终输出格式化报告到终端。
VecHashMap闭包迭代器文件 I/O字符串处理