Skip to content

实战总结

> 综合运用数组与Vec知识,通过实战示例巩固集合操作,识别常见错误与性能优化技巧。

完整示例

示例 1:统计计算

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

    // 总和
    let sum: i32 = numbers.iter().sum();

    // 平均值
    let avg = sum as f64 / numbers.len() as f64;

    // 最大值和最小值
    let max = numbers.iter().max().unwrap();
    let min = numbers.iter().min().unwrap();

    // 中位数(需要排序)
    let mut sorted = numbers.clone();
    sorted.sort();
    let mid = sorted.len() / 2;
    let median = if sorted.len() % 2 == 0 {
        (sorted[mid - 1] + sorted[mid]) as f64 / 2.0
    } else {
        sorted[mid] as f64
    };

    // 众数(出现最多的元素)
    use std::collections::HashMap;
    let mut counts = HashMap::new();
    for &num in &numbers {
        *counts.entry(num).or_insert(0) += 1;
    }
    let mode = counts.iter().max_by_key(|&(_, count)| count).unwrap().0;

    println!("数据:{:?}", numbers);
    println!("总和:{}", sum);
    println!("平均值:{:.2}", avg);
    println!("最大值:{}", max);
    println!("最小值:{}", min);
    println!("中位数:{:.2}", median);
    println!("众数:{}", mode);
}
▶ Run

示例 2:待办事项列表

rust
struct TodoList {
    items: Vec<TodoItem>,
}

#[derive(Debug)]
struct TodoItem {
    description: String,
    completed: bool,
}

impl TodoItem {
    fn new(description: String) -> Self {
        TodoItem {
            description,
            completed: false,
        }
    }
}

impl TodoList {
    fn new() -> Self {
        TodoList {
            items: Vec::new(),
        }
    }

    fn add(&mut self, description: String) {
        self.items.push(TodoItem::new(description));
        println!("已添加:{}", description);
    }

    fn complete(&mut self, index: usize) -> Result<(), String> {
        if index < self.items.len() {
            self.items[index].completed = true;
            Ok(())
        } else {
            Err(format!("索引 {} 不存在", index))
        }
    }

    fn remove(&mut self, index: usize) -> Result<TodoItem, String> {
        if index < self.items.len() {
            Ok(self.items.remove(index))
        } else {
            Err(format!("索引 {} 不存在", index))
        }
    }

    fn list(&self) {
        if self.items.is_empty() {
            println!("待办事项为空");
            return;
        }

        println!("\n待办事项列表:");
        println!("{:-<40}", "");
        for (i, item) in self.items.iter().enumerate() {
            let status = if item.completed { "✓" } else { "○" };
            println!("{}. [{}] {}", i + 1, status, item.description);
        }
        println!("{:-<40}", "");
    }

    fn pending_count(&self) -> usize {
        self.items.iter().filter(|item| !item.completed).count()
    }
}

fn main() {
    let mut todo = TodoList::new();

    todo.add(String::from("学习 Rust"));
    todo.add(String::from("写代码"));
    todo.add(String::from("跑步"));
    todo.add(String::from("读书"));

    todo.list();
    println!("待完成:{} 项", todo.pending_count());

    todo.complete(1).unwrap();
    todo.complete(3).unwrap();

    println!("\n完成两项后:");
    todo.list();

    todo.remove(2).unwrap();

    println!("\n移除一项后:");
    todo.list();
}
▶ Run

示例 3:矩阵运算

rust
type Matrix = Vec<Vec<f64>>;

fn create_matrix(rows: usize, cols: usize, value: f64) -> Matrix {
    vec![vec![value; cols]; rows]
}

fn identity_matrix(size: usize) -> Matrix {
    let mut mat = create_matrix(size, size, 0.0);
    for i in 0..size {
        mat[i][i] = 1.0;
    }
    mat
}

fn print_matrix(matrix: &Matrix, name: &str) {
    println!("{}:", name);
    for row in matrix {
        print!("  [");
        for (i, val) in row.iter().enumerate() {
            if i > 0 {
                print!(", ");
            }
            print!("{:6.2}", val);
        }
        println!("]");
    }
    println!();
}

fn matrix_add(a: &Matrix, b: &Matrix) -> Matrix {
    a.iter()
        .zip(b.iter())
        .map(|(row_a, row_b)| {
            row_a.iter().zip(row_b.iter()).map(|(&a, &b)| a + b).collect()
        })
        .collect()
}

fn scalar_multiply(matrix: &Matrix, scalar: f64) -> Matrix {
    matrix
        .iter()
        .map(|row| row.iter().map(|&val| val * scalar).collect())
        .collect()
}

fn transpose(matrix: &Matrix) -> Matrix {
    if matrix.is_empty() {
        return Vec::new();
    }
    let rows = matrix.len();
    let cols = matrix[0].len();
    (0..cols)
        .map(|j| (0..rows).map(|i| matrix[i][j]).collect())
        .collect()
}

fn main() {
    // 创建矩阵
    let a = vec![
        vec![1.0, 2.0, 3.0],
        vec![4.0, 5.0, 6.0],
    ];

    let b = vec![
        vec![7.0, 8.0, 9.0],
        vec![10.0, 11.0, 12.0],
    ];

    print_matrix(&a, "矩阵 A");
    print_matrix(&b, "矩阵 B");

    // 矩阵加法
    let sum = matrix_add(&a, &b);
    print_matrix(&sum, "A + B");

    // 标量乘法
    let scaled = scalar_multiply(&a, 2.0);
    print_matrix(&scaled, "A * 2");

    // 转置
    let transposed = transpose(&a);
    print_matrix(&transposed, "A 的转置");

    // 单位矩阵
    let identity = identity_matrix(4);
    print_matrix(&identity, "4x4 单位矩阵");
}
▶ Run

示例 4:简单的字符串处理器

rust
fn main() {
    let text = String::from("Hello, Rust! This is a test.");

    // 转换为字符 Vec
    let chars: Vec<char> = text.chars().collect();
    println!("字符数:{}", chars.len());

    // 过滤元音
    let vowels: Vec<char> = chars
        .iter()
        .copied()
        .filter(|c| "aeiouAEIOU".contains(*c))
        .collect();
    println!("元音:{:?}", vowels);

    // 转换为大写
    let upper: Vec<char> = chars
        .iter()
        .map(|c| c.to_uppercase().next().unwrap())
        .collect();
    let upper_string: String = upper.into_iter().collect();
    println!("大写:{}", upper_string);

    // 分词
    let words: Vec<&str> = text.split_whitespace().collect();
    println!("单词:{:?}", words);

    // 单词长度统计
    let word_lengths: Vec<usize> = words.iter().map(|w| w.len()).collect();
    println!("单词长度:{:?}", word_lengths);

    // 连接字符串
    let joined = words.join("-");
    println!("连接:{}", joined);
}
▶ Run

性能优化技巧

预分配容量

rust
// ❌ 低效:可能多次重新分配
fn inefficient() -> Vec<i32> {
    let mut v = Vec::new();
    for i in 0..1000 {
        v.push(i);
    }
    v
}

// ✅ 高效:预分配容量
fn efficient() -> Vec<i32> {
    let mut v = Vec::with_capacity(1000);
    for i in 0..1000 {
        v.push(i);
    }
    v
}

// ✅ 使用 collect(通常能推断大小)
fn best() -> Vec<i32> {
    (0..1000).collect()
}
▶ Run

避免不必要的复制

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

    // ❌ 不必要的复制
    fn process_owned(v: Vec<i32>) -> i32 {
        v.iter().sum()
    }
    let result = process_owned(data.clone());  // 复制了整个 Vec

    // ✅ 使用借用
    fn process_borrowed(v: &[i32]) -> i32 {
        v.iter().sum()
    }
    let result = process_borrowed(&data);  // 只传递引用
}
▶ Run

使用 drain 清空并获取元素

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

    // ❌ 先迭代再清空(两次遍历)
    let sum: i32 = v.iter().sum();
    v.clear();

    // ✅ 使用 drain(一次遍历并清空)
    let sum: i32 = v.drain(..).sum();
    // v 现在是空的
}
▶ Run

常见错误

错误 1:忘记 mut

rust
fn main() {
    // ❌ 错误:需要 mut 才能修改
    // let v = Vec::new();
    // v.push(1);

    // ✅ 正确
    let mut v = Vec::new();
    v.push(1);

    // 数组同理
    // let arr = [1, 2, 3];
    // arr[0] = 10;  // ❌ 需要 mut

    let mut arr = [1, 2, 3];
    arr[0] = 10;  // ✅
}
▶ Run

错误 2:数组越界

rust
fn main() {
    let numbers = [1, 2, 3];

    // ❌ 会导致 panic
    // let value = numbers[10];

    // ✅ 使用 get 安全访问
    match numbers.get(10) {
        Some(v) => println!("{}", v),
        None => println!("索引超出范围"),
    }

    // ✅ 或者先检查长度
    let index = 10;
    if index < numbers.len() {
        println!("{}", numbers[index]);
    } else {
        println!("索引 {} 超出范围", index);
    }
}
▶ Run

错误信息:

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 10'

错误 3:迭代时修改 Vec

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

    // ❌ 错误:迭代时不能修改
    // for i in &v {
    //     v.push(*i);  // 借用冲突
    // }

    // ✅ 正确:收集后扩展
    let to_add: Vec<i32> = v.iter().copied().collect();
    v.extend(to_add);

    // ✅ 或使用索引
    let len = v.len();
    for i in 0..len {
        let val = v[i] * 2;
        v.push(val);
    }
}
▶ Run

错误信息:

error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable

错误 4:返回局部 Vec 的切片

rust
// ❌ 错误:返回悬垂引用
// fn get_slice() -> &[i32] {
//     let v = vec![1, 2, 3];
//     &v  // v 在函数结束时被释放
// }

// ✅ 正确:返回 Vec
fn get_vec() -> Vec<i32> {
    vec![1, 2, 3]
}

fn main() {
    let v = get_vec();
    println!("{:?}", v);
}
▶ Run

错误 5:误用 dedup

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

    // ❌ dedup 只移除连续的重复元素
    v.dedup();
    println!("{:?}", v);  // [3, 1, 2, 1, 3](没有变化!)

    // ✅ 正确:先排序再去重
    let mut v = vec![3, 1, 2, 1, 3];
    v.sort();
    v.dedup();
    println!("{:?}", v);  // [1, 2, 3]
}
▶ Run

调试技巧

打印调试信息

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

    // 基本调试输出
    println!("{:?}", v);

    // 美化格式
    println!("{:#?}", v);

    // 使用 dbg! 宏
    let result = dbg!(v.len()) * 2;

    // dbg! 返回值的引用,可以用于链式调用
    let v = vec![1, 2, 3];
    let sum: i32 = dbg!(v).iter().sum();
}
▶ Run

检查容量变化

rust
fn main() {
    let mut v: Vec<i32> = Vec::with_capacity(4);

    println!("初始:len={}, cap={}", v.len(), v.capacity());

    for i in 0..10 {
        v.push(i);
        println!("push({}): len={}, cap={}", i, v.len(), v.capacity());
    }
}
▶ Run

练习

练习 1:基本操作

创建一个 Vec,实现以下功能:

  1. 添加数字 1-10
  2. 计算所有偶数的和
  3. 移除最后一个元素
  4. 在开头插入 0
  5. 打印最终结果

练习 2:字符串处理

编写函数,接受字符串 Vec,返回:

  1. 所有字符串连接成一个大写字符串
  2. 最长字符串的长度
  3. 所有字符串的平均长度

练习 3:栈实现

使用 Vec 实现一个简单的栈:

  • push(item) - 入栈
  • pop() - 出栈
  • peek() - 查看栈顶
  • is_empty() - 判断是否为空

练习 4:向量运算

实现向量(Vec<f64>)的基本运算:

  • dot_product(a, b) - 点积
  • magnitude(v) - 模长
  • normalize(v) - 归一化
  • add(a, b) - 向量加法

小结

数组与 Vec 对比

特性数组Vec
类型[T; N]Vec<T>
长度固定(编译时)可变(运行时)
存储栈上(通常)堆上
大小N * sizeof(T)len * sizeof(T) + 开销
性能稍快稍慢(但更灵活)
方法较少丰富

常用方法速查

方法数组Vec说明
len()获取长度
is_empty()判断为空
first()/last()首尾元素
get(i)安全访问
iter()/iter_mut()迭代器
push()/pop()末尾操作
insert()/remove()插入/删除
extend()批量添加
clear()清空

关键要点

  1. 数组用于固定大小的集合,存储在栈上,性能最优
  2. Vec用于动态集合,可自动增长,使用最广泛
  3. 索引访问会进行边界检查,越界会 panic
  4. 使用 get() 方法可以安全访问,返回 Option
  5. Vec 扩容时会重新分配内存,预分配容量可优化性能
  6. 函数参数优先使用切片 &[T],可同时接受数组和 Vec

练习题

详见:练习题