01. Vec:动态数组
Vec 是 Rust 最常用的集合,在堆上分配连续内存,和 C++ 的 vector 类似。push 尾部添加,pop 尾部移除,len 获取长度。用索引 [i] 访问,越界会 panic;get(i) 返回 Option 更安全。遍历用 for in 或 iter 迭代器。可以预分配容量避免频繁扩容拷贝。
rust
fn main() {
let mut v: Vec<i32> = Vec::new();
v.push(1);
v.push(2);
v.push(3);
// 宏创建
let v2 = vec![1, 2, 3, 4, 5];
// 访问
let third = &v[2]; // panic 如果越界
let third = v.get(2); // 返回 Option,安全
// 遍历
for i in &v {
println!("{}", i);
}
// 可变遍历
for i in &mut v {
*i += 10;
}
// 预分配
let mut v3 = Vec::with_capacity(100);
}访问 Vec 推荐用 get 而不是索引,它返回 Option 可以用 match 优雅处理越界。
02. String:堆上字符串
Rust 的 String 是 Vec<u8> 的封装,保证存储的是合法 UTF-8。push_str 追加字符串,push 追加字符,+ 号拼接(会转移左边所有权),format! 宏拼接不转移所有权最灵活。字符串索引 [i] 不能直接用因为 UTF-8 字节不固定,用 chars() 迭代字符。
rust
fn main() {
let mut s = String::from("你好");
s.push_str(",世界"); // 追加字符串
s.push('!'); // 追加字符
// 拼接(多种方式)
let s1 = String::from("Hello");
let s2 = String::from("World");
let s3 = s1 + " " + &s2; // + 号,s1 所有权转移了
// println!("{}", s1); // 报错!
let s4 = format!("{} {}", s2, "Rust"); // 推荐!不转移所有权
// 迭代字符(不是字节)
for c in "你好".chars() {
println!("{}", c); // 你 好
}
}String 不能用 s[0] 这样索引,因为 UTF-8 中一个字可能占多个字节。用 chars().nth(0)。
03. HashMap:键值对
HashMap 不在 prelude 里需要 use 导入。insert 插入/更新,get 返回 Option<&V>,entry 方法用于收集词频这种场景最方便(如果存在就更新,不存在就插入)。for 遍历顺序不固定因为是无序的。
rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert("Blue", 10);
scores.insert("Red", 50);
// 获取
let blue_score = scores.get("Blue"); // Some(&10)
// entry 模式 - 词频统计
let text = "hello world hello";
let mut word_count = HashMap::new();
for word in text.split_whitespace() {
let count = word_count.entry(word).or_insert(0);
*count += 1;
}
// word_count: {"hello": 2, "world": 1}
// 遍历
for (key, value) in &scores {
println!("{}: {}", key, value);
}
}entry().or_insert() 是 HashMap 的招牌操作,一次查找搞定存在就更新不存在就插入。
04. 迭代器 Iterator
Rust 的迭代器是惰性的,不调用消费方法不会执行。iter() 返回不可变引用迭代器,iter_mut() 可变引用迭代器,into_iter() 所有权转移迭代器。链式调用 map、filter、collect 等组合器非常强大,性能接近手写循环因为迭代器是零成本抽象。
rust
fn main() {
let v = vec![1, 2, 3, 4, 5];
// 链式操作
let even_squares: Vec<i32> = v.iter()
.filter(|&x| x % 2 == 0)
.map(|&x| x * x)
.collect();
// [4, 16]
// 消费方法
let sum: i32 = v.iter().sum();
let max = v.iter().max().unwrap();
let any_even = v.iter().any(|&x| x % 2 == 0);
// enumerate 带索引
for (i, val) in v.iter().enumerate() {
println!("{}: {}", i, val);
}
// 无限迭代器
let fib: Vec<i32> = (0..).take(10).collect(); // [0,1,2,...,9]
}对于链式迭代器,编译器会优化成接近手写循环的效率,放心用。
05. 枚举 Option 和 Result
Option<T> 替代了 null,有值就是 Some(T),没有就是 None。Result<T, E> 表示可能出错的操作,Ok(T) 成功,Err(E) 失败。这两个枚举配合 match、if let、? 运算符构成了 Rust 错误处理的基石。? 运算符是语法糖:如果是 Ok 就解包,Err 就直接向上返回错误。
rust
fn divide(a: i32, b: i32) -> Result<f64, String> {
if b == 0 {
return Err(String::from("除数不能为零"));
}
Ok(a as f64 / b as f64)
}
fn main() {
// Option 处理
let config = Some(8080);
match config {
Some(p) => println!("端口: {}", p),
None => println!("使用默认"),
}
if let Some(p) = config {
println!("端口: {}", p);
}
// Result 处理
match divide(10, 2) {
Ok(v) => println!("结果: {}", v),
Err(e) => println!("错误: {}", e),
}
// ? 运算符
fn read_config() -> Result<String, String> {
let content = std::fs::read_to_string("config.toml")
.map_err(|e| format!("读配置失败: {}", e))?;
Ok(content)
}
}? 运算符是 Rust 错误处理最常用的语法,让错误传播无比简洁。只能在返回 Result 或 Option 的函数里用。
知识测验
第 1/5 题正确 0
Vec 用索引访问和 get 访问的区别?
下一节
下一节 错误处理