ToolkitX
知识库工具箱

集合类型

Vec, HashMap, String, 迭代器

25min·进阶

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 访问的区别?

下一节

错误处理

下一节