16·复合类型入门

Vec 动态数组

Vec 动态数组

学习目标

  1. 创建和初始化 Vec
  2. 掌握增删改查操作
  3. 理解所有权和借用规则
  4. 掌握迭代器和常用方法

核心概念

创建 Vec

fn main() {
    let v1: Vec<i32> = Vec::new();          // 空 Vec
    let v2 = vec![1, 2, 3];                 // 宏创建
    let v3 = vec![0; 10];                   // 10 个 0
    let v4 = Vec::with_capacity(100);       // 预分配容量
}

增删改查

fn main() {
    let mut v = vec![1, 2, 3];

    // 增
    v.push(4);                    // 尾部追加
    v.insert(0, 0);              // 指定位置插入
    v.extend([5, 6, 7]);         // 批量追加

    // 删
    v.pop();                      // 移除并返回最后一个
    v.remove(0);                  // 移除指定索引
    v.retain(|&x| x > 2);        // 保留满足条件的
    v.clear();                    // 清空

    // 改
    let mut v = vec![1, 2, 3];
    v[0] = 10;                    // 通过索引修改

    // 查
    let first = v[0];             // 索引访问(越界 panic)
    let safe = v.get(0);          // 安全访问(返回 Option)
    let len = v.len();
    let is_empty = v.is_empty();
    let contains = v.contains(&2);
}

所有权

fn main() {
    let mut v = vec![String::from("hello"), String::from("world")];

    // ❌ 移动出 Vec
    // let first = v[0];  // 编译错误:不能移出借用

    // ✅ 借用
    let first = &v[0];
    println!("{}", first);

    // ✅ 克隆
    let first = v[0].clone();

    // ✅ swap_remove(移出并用最后一个填补)
    let first = v.swap_remove(0);
    println!("{}", first);  // "hello",v 变成 ["world"]
}

迭代

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

    // 不可变迭代
    for val in &v {
        println!("{}", val);
    }

    // 可变迭代
    let mut v = vec![1, 2, 3];
    for val in &mut v {
        *val *= 2;
    }

    // 消耗性迭代(迭代后 v 不可用)
    let v = vec![1, 2, 3];
    for val in v {
        println!("{}", val);
    }
    // println!("{:?}", v);  // ❌ 已移动
}

常用方法

fn main() {
    let mut v = vec![3, 1, 4, 1, 5, 9, 2, 6];

    // 排序
    v.sort();                         // 升序
    v.sort_by(|a, b| b.cmp(a));      // 降序
    v.sort_unstable();                // 不稳定排序(更快)

    // 去重(需先排序)
    v.sort();
    v.dedup();

    // 切片
    let slice = &v[1..4];
    let (left, right) = v.split_at(3);

    // 窗口和块
    for window in v.windows(3) {
        println!("{:?}", window);     // 滑动窗口
    }
    for chunk in v.chunks(2) {
        println!("{:?}", chunk);      // 固定大小块
    }

    // 连接
    let v = vec![1, 2, 3];
    let sum: i32 = v.iter().sum();
    let product: i32 = v.iter().product();
    let max = v.iter().max();
    let min = v.iter().min();
}

二维 Vec

fn main() {
    // 创建 3x4 矩阵
    let mut matrix = vec![vec![0; 4]; 3];

    matrix[1][2] = 42;
    println!("{:?}", matrix);

    // 遍历
    for (i, row) in matrix.iter().enumerate() {
        for (j, &val) in row.iter().enumerate() {
            print!("{:4}", val);
        }
        println!();
    }
}

实践练习

练习 1:去重保序

fn dedup_ordered<T: PartialEq>(v: &mut Vec<T>) {
    let mut i = 0;
    while i < v.len() {
        let mut j = i + 1;
        while j < v.len() {
            if v[i] == v[j] {
                v.remove(j);
            } else {
                j += 1;
            }
        }
        i += 1;
    }
}

fn main() {
    let mut v = vec![1, 3, 2, 3, 1, 4, 2];
    dedup_ordered(&mut v);
    println!("{:?}", v);  // [1, 3, 2, 4]
}

练习 2:矩阵转置

fn transpose(matrix: &Vec<Vec<i32>>) -> Vec<Vec<i32>> {
    let rows = matrix.len();
    let cols = matrix[0].len();
    let mut result = vec![vec![0; rows]; cols];
    for i in 0..rows {
        for j in 0..cols {
            result[j][i] = matrix[i][j];
        }
    }
    result
}

fn main() {
    let m = vec![
        vec![1, 2, 3],
        vec![4, 5, 6],
    ];
    let t = transpose(&m);
    println!("{:?}", t);  // [[1, 4], [2, 5], [3, 6]]
}

练习 3:滑动窗口最大值

fn max_sliding_window(v: &[i32], k: usize) -> Vec<i32> {
    v.windows(k).map(|w| *w.iter().max().unwrap()).collect()
}

fn main() {
    let data = vec![1, 3, -1, -3, 5, 3, 6, 7];
    let result = max_sliding_window(&data, 3);
    println!("{:?}", result);  // [3, 3, 5, 5, 6, 7]
}

常见错误

1. 越界访问

let v = vec![1, 2, 3];
// let x = v[10];  // ❌ panic: index out of bounds
let x = v.get(10);  // ✅ 返回 None

2. 迭代时修改

let mut v = vec![1, 2, 3];
// for val in &v {
//     v.push(*val);  // ❌ 不能在不可变借用期间可变借用
// }

3. 移动出 Vec

let v = vec![String::from("hello")];
// let s = v[0];  // ❌ 不能移出借用
let s = v.into_iter().next().unwrap();  // ✅ 消耗性迭代

小结

操作语法
创建vec![...], Vec::new()
追加push, extend
访问v[i], v.get(i)
迭代for x in &v
排序sort, sort_by
过滤retain, iter().filter()

练习编辑器

rust
Loading...