Rust集合类型(上):Vector的动态数组

引言:从固定大小到动态增长

在前面的文章中,我们学习了Rust的基础数据类型和简单的数据结构。现在,我们将进入Rust集合类型的世界,首先探讨最常用且最灵活的集合——Vector(动态数组)。Vector允许我们在运行时动态地添加、删除和修改元素,是处理可变长度数据序列的强大工具。本文将深入解析Vector的内部机制、性能特征以及在实际项目中的应用。

理解Vector的基本概念

1.1 什么是Vector?

Vector(Vec<T>)是Rust标准库中提供的动态数组实现,具有以下核心特性:

  • 动态大小:可以在运行时增长或缩小
  • 连续内存:元素在内存中连续存储
  • 类型安全:所有元素必须是相同类型
  • 高效访问:通过索引的访问时间是O(1)
  • 自动内存管理:自动处理内存分配和释放

1.2 Vector与数组的对比

理解Vector与固定大小数组的区别很重要:

特性 数组 ([T; N]) Vector (Vec<T>)
大小 编译时固定 运行时可变
内存 栈分配 堆分配
性能 无分配开销 有分配开销
灵活性 有限

Vector的基本操作

2.1 创建Vector

有多种方式可以创建Vector:

fn main() {
    // 方法1: 使用Vec::new()创建空Vector
    let mut v1: Vec<i32> = Vec::new();
    println!("空Vector: {:?}", v1);

    // 方法2: 使用vec!宏创建并初始化
    let v2 = vec![1, 2, 3, 4, 5];
    println!("初始化的Vector: {:?}", v2);

    // 方法3: 使用Vec::with_capacity预分配容量
    let mut v3 = Vec::with_capacity(10);
    println!("预分配容量的Vector: 长度={}, 容量={}", v3.len(), v3.capacity());

    // 方法4: 从迭代器创建
    let v4: Vec<i32> = (0..5).collect();
    println!("从迭代器创建的Vector: {:?}", v4);

    // 方法5: 从数组创建
    let arr = [1, 2, 3];
    let v5 = arr.to_vec();
    println!("从数组创建的Vector: {:?}", v5);
}

2.2 添加和删除元素

Vector提供了多种方法来修改内容:

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

    // 添加元素
    numbers.push(4);
    numbers.push(5);
    println!("添加后: {:?}", numbers);

    // 在指定位置插入元素
    numbers.insert(1, 10); // 在索引1处插入10
    println!("插入后: {:?}", numbers);

    // 删除并返回最后一个元素
    let last = numbers.pop();
    println!("删除的元素: {:?}, 剩余: {:?}", last, numbers);

    // 删除指定位置的元素
    let removed = numbers.remove(1); // 删除索引1处的元素
    println!("删除的元素: {}, 剩余: {:?}", removed, numbers);

    // 清空Vector
    numbers.clear();
    println!("清空后: {:?}, 长度: {}", numbers, numbers.len());
}

2.3 访问元素

有多种方式可以安全地访问Vector中的元素:

fn main() {
    let numbers = vec![10, 20, 30, 40, 50];

    // 方法1: 使用索引(可能panic)
    let third = numbers[2];
    println!("第三个元素: {}", third);

    // 方法2: 使用get方法(安全)
    match numbers.get(2) {
        Some(third) => println!("第三个元素: {}", third),
        None => println!("索引2超出范围"),
    }

    // 方法3: 处理越界访问
    let tenth = numbers.get(10);
    if tenth.is_none() {
        println!("索引10超出范围");
    }

    // 方法4: 使用get_mut获取可变引用
    let mut mutable_numbers = vec![1, 2, 3];
    if let Some(elem) = mutable_numbers.get_mut(1) {
        *elem = 100; // 修改第二个元素
    }
    println!("修改后: {:?}", mutable_numbers);

    // 方法5: 第一个和最后一个元素
    if let Some(first) = numbers.first() {
        println!("第一个元素: {}", first);
    }
    if let Some(last) = numbers.last() {
        println!("最后一个元素: {}", last);
    }
}

Vector的所有权和借用

3.1 所有权规则

理解Vector的所有权行为很重要:

fn main() {
    // Vector拥有其元素的所有权
    let v = vec![String::from("hello"), String::from("world")];

    // 当Vector离开作用域时,所有元素也会被丢弃
    // 这里v和其中的字符串都会被清理
}

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

    // 获取元素的不可变引用
    let first = &v[0];
    // let second = &mut v[1]; // 编译错误:不能同时有可变和不可变引用
    println!("第一个元素: {}", first);

    // 现在可以获取可变引用
    let second = &mut v[1];
    *second = 100;

    println!("修改后的Vector: {:?}", v);
}

3.2 迭代Vector

有多种方式可以迭代Vector:

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

    // 方法1: 使用for循环(不可变引用)
    println!("不可变迭代:");
    for number in &numbers {
        println!("{}", number);
    }

    // 方法2: 使用for循环(可变引用)
    let mut mutable_numbers = vec![1, 2, 3];
    println!("\n可变迭代:");
    for number in &mut mutable_numbers {
        *number *= 2; // 修改每个元素
        println!("{}", number);
    }

    // 方法3: 使用for循环(获取所有权)
    println!("\n获取所有权迭代:");
    for number in numbers {
        println!("{}", number);
    }
    // numbers不再可用,因为所有权被移动了

    // 方法4: 使用iter()方法
    let new_numbers = vec![10, 20, 30];
    println!("\n使用iter():");
    for number in new_numbers.iter() {
        println!("{}", number);
    }
    // new_numbers仍然可用

    // 方法5: 使用iter_mut()方法
    let mut yet_another = vec![1, 2, 3];
    println!("\n使用iter_mut():");
    for number in yet_another.iter_mut() {
        *number += 10;
        println!("{}", number);
    }
    println!("修改后: {:?}", yet_another);
}

Vector的内部机制

4.1 容量和长度

理解Vector的容量管理对于性能优化很重要:

fn demonstrate_capacity() {
    let mut v = Vec::new();
    println!("初始状态 - 长度: {}, 容量: {}", v.len(), v.capacity());

    // 添加元素,观察容量增长
    for i in 0..20 {
        v.push(i);
        println!("添加{}后 - 长度: {}, 容量: {}", i, v.len(), v.capacity());
    }

    // 缩减容量
    v.shrink_to_fit();
    println!("缩减后 - 长度: {}, 容量: {}", v.len(), v.capacity());

    // 保留容量
    v.truncate(10);
    println!("截断后 - 长度: {}, 容量: {}", v.len(), v.capacity());

    // 明确设置容量
    v.reserve(50);
    println!("保留50容量后 - 长度: {}, 容量: {}", v.len(), v.capacity());
}

fn main() {
    demonstrate_capacity();
}

4.2 内存布局

Vector在内存中的布局如下:

struct Vec<T> {
    ptr: *mut T,      // 指向堆上数据的指针
    cap: usize,       // 容量(分配的内存大小)
    len: usize,       // 长度(实际元素数量)
}

当Vector需要增长时,它会:

  1. 分配新的更大的内存块
  2. 将现有元素复制到新位置
  3. 释放旧的内存块
  4. 更新指针和容量

高级Vector操作

5.1 切片操作

Vector可以方便地转换为切片:

fn demonstrate_slices() {
    let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

    // 获取整个Vector的切片
    let full_slice: &[i32] = &numbers;
    println!("完整切片: {:?}", full_slice);

    // 获取部分切片
    let partial_slice = &numbers[2..7]; // 索引2到6
    println!("部分切片: {:?}", partial_slice);

    // 获取可变切片
    let mut mutable_numbers = numbers;
    let mutable_slice = &mut mutable_numbers[3..8];

    // 修改切片中的元素
    for elem in mutable_slice {
        *elem *= 2;
    }
    println!("修改后的Vector: {:?}", mutable_numbers);

    // 使用split_at分割Vector
    let (left, right) = mutable_numbers.split_at(5);
    println!("分割 - 左: {:?}, 右: {:?}", left, right);

    // 使用split_at_mut进行可变分割
    let (left_mut, right_mut) = mutable_numbers.split_at_mut(5);
    left_mut[0] = 100;
    right_mut[0] = 200;
    println!("可变分割后: {:?}", mutable_numbers);
}

fn main() {
    demonstrate_slices();
}

5.2 搜索和过滤

Vector提供了强大的搜索和过滤功能:

fn demonstrate_searching() {
    let numbers = vec![10, 20, 30, 40, 50, 30, 60];

    // 线性搜索
    if let Some(index) = numbers.iter().position(|&x| x == 30) {
        println!("找到30在索引: {}", index);
    }

    // 从末尾搜索
    if let Some(index) = numbers.iter().rposition(|&x| x == 30) {
        println!("从末尾找到30在索引: {}", index);
    }

    // 检查包含
    println!("包含25: {}", numbers.contains(&25));
    println!("包含30: {}", numbers.contains(&30));

    // 过滤元素
    let even_numbers: Vec<i32> = numbers.iter()
        .filter(|&&x| x % 20 == 0)
        .cloned()
        .collect();
    println!("能被20整除的数: {:?}", even_numbers);

    // 查找最大最小值
    if let Some(max) = numbers.iter().max() {
        println!("最大值: {}", max);
    }
    if let Some(min) = numbers.iter().min() {
        println!("最小值: {}", min);
    }
}

fn main() {
    demonstrate_searching();
}

5.3 排序和去重

fn demonstrate_sorting() {
    let mut numbers = vec![5, 2, 8, 1, 9, 3, 2, 8];
    println!("原始: {:?}", numbers);

    // 排序
    numbers.sort();
    println!("排序后: {:?}", numbers);

    // 去重
    numbers.dedup();
    println!("去重后: {:?}", numbers);

    // 反向排序
    numbers.sort_by(|a, b| b.cmp(a));
    println!("反向排序: {:?}", numbers);

    // 自定义排序
    let mut words = vec!["banana", "apple", "cherry", "date"];
    words.sort_by_key(|w| w.len());
    println!("按长度排序: {:?}", words);

    // 二分搜索(需要已排序)
    numbers.sort();
    match numbers.binary_search(&5) {
        Ok(index) => println!("找到5在索引: {}", index),
        Err(_) => println!("未找到5"),
    }
}

fn main() {
    demonstrate_sorting();
}

实际应用:学生成绩管理系统

6.1 完整的系统实现

让我们创建一个学生成绩管理系统来演示Vector的实际应用:

#[derive(Debug, Clone)]
struct Student {
    name: String,
    grades: Vec<f64>,
}

impl Student {
    fn new(name: String) -> Self {
        Student {
            name,
            grades: Vec::new(),
        }
    }

    fn add_grade(&mut self, grade: f64) {
        self.grades.push(grade);
    }

    fn average_grade(&self) -> Option<f64> {
        if self.grades.is_empty() {
            None
        } else {
            let sum: f64 = self.grades.iter().sum();
            Some(sum / self.grades.len() as f64)
        }
    }

    fn highest_grade(&self) -> Option<f64> {
        self.grades.iter().cloned().reduce(f64::max)
    }

    fn lowest_grade(&self) -> Option<f64> {
        self.grades.iter().cloned().reduce(f64::min)
    }
}

struct GradeBook {
    students: Vec<Student>,
}

impl GradeBook {
    fn new() -> Self {
        GradeBook {
            students: Vec::new(),
        }
    }

    fn add_student(&mut self, name: String) {
        self.students.push(Student::new(name));
    }

    fn find_student_mut(&mut self, name: &str) -> Option<&mut Student> {
        self.students.iter_mut().find(|s| s.name == name)
    }

    fn find_student(&self, name: &str) -> Option<&Student> {
        self.students.iter().find(|s| s.name == name)
    }

    fn class_average(&self) -> Option<f64> {
        let averages: Vec<f64> = self.students
            .iter()
            .filter_map(|s| s.average_grade())
            .collect();

        if averages.is_empty() {
            None
        } else {
            Some(averages.iter().sum::<f64>() / averages.len() as f64)
        }
    }

    fn top_students(&self, count: usize) -> Vec<(&Student, f64)> {
        let mut student_averages: Vec<(&Student, f64)> = self.students
            .iter()
            .filter_map(|s| s.average_grade().map(|avg| (s, avg)))
            .collect();

        // 按平均分降序排序
        student_averages.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());

        // 返回前count名学生
        student_averages.into_iter().take(count).collect()
    }

    fn remove_student(&mut self, name: &str) -> bool {
        if let Some(pos) = self.students.iter().position(|s| s.name == name) {
            self.students.remove(pos);
            true
        } else {
            false
        }
    }

    fn display_summary(&self) {
        println!("=== 班级成绩汇总 ===");
        println!("学生总数: {}", self.students.len());

        if let Some(class_avg) = self.class_average() {
            println!("班级平均分: {:.2}", class_avg);
        }

        println!("\n学生详情:");
        for student in &self.students {
            print!("{}: 成绩{:?}", student.name, student.grades);
            if let Some(avg) = student.average_grade() {
                print!(" (平均: {:.2})", avg);
            }
            println!();
        }

        println!("\n优秀学生:");
        for (student, avg) in self.top_students(3) {
            println!("{}: {:.2}", student.name, avg);
        }
    }
}

fn main() {
    let mut grade_book = GradeBook::new();

    // 添加学生
    grade_book.add_student("张三".to_string());
    grade_book.add_student("李四".to_string());
    grade_book.add_student("王五".to_string());

    // 添加成绩
    if let Some(student) = grade_book.find_student_mut("张三") {
        student.add_grade(85.0);
        student.add_grade(92.0);
        student.add_grade(78.0);
    }

    if let Some(student) = grade_book.find_student_mut("李四") {
        student.add_grade(90.0);
        student.add_grade(88.0);
        student.add_grade(95.0);
    }

    if let Some(student) = grade_book.find_student_mut("王五") {
        student.add_grade(75.0);
        student.add_grade(82.0);
        student.add_grade(79.0);
    }

    // 显示汇总
    grade_book.display_summary();

    // 演示其他操作
    println!("\n=== 其他操作演示 ===");

    // 查找学生
    if let Some(student) = grade_book.find_student("张三") {
        println!("张三的最高分: {:?}", student.highest_grade());
        println!("张三的最低分: {:?}", student.lowest_grade());
    }

    // 移除学生
    if grade_book.remove_student("王五") {
        println!("成功移除王五");
    }

    // 显示更新后的汇总
    grade_book.display_summary();
}

性能优化技巧

7.1 容量预分配

fn demonstrate_performance() {
    // 不好的做法:频繁重新分配
    let mut slow_vec = Vec::new();
    for i in 0..1000 {
        slow_vec.push(i); // 可能多次重新分配
    }

    // 好的做法:预分配容量
    let mut fast_vec = Vec::with_capacity(1000);
    for i in 0..1000 {
        fast_vec.push(i); // 无重新分配
    }

    println!("慢速Vector最终容量: {}", slow_vec.capacity());
    println!("快速Vector最终容量: {}", fast_vec.capacity());
}

7.2 避免不必要的克隆

fn avoid_unnecessary_clones() {
    let data = vec![String::from("hello"), String::from("world")];

    // 不好的做法:不必要的克隆
    let cloned_data: Vec<String> = data.iter().cloned().collect();

    // 好的做法:使用引用
    let referenced_data: Vec<&String> = data.iter().collect();

    // 或者使用切片
    let slice_data: &[String] = &data;

    println!("克隆数据长度: {}", cloned_data.len());
    println!("引用数据长度: {}", referenced_data.len());
    println!("切片数据长度: {}", slice_data.len());
}

结论

Vector是Rust中最常用且最灵活的集合类型,通过本文的学习,你应该已经掌握了:

  1. Vector的基本概念:动态数组的特性和优势
  2. 创建和初始化:多种创建Vector的方法
  3. 元素操作:添加、删除、访问和修改元素
  4. 迭代和搜索:多种迭代方式和搜索算法
  5. 排序和过滤:数据整理和筛选技术
  6. 性能优化:容量管理和避免不必要的开销
  7. 实际应用:在真实项目中使用Vector
  8. 内存管理:理解Vector的内部机制

Vector为处理动态数据序列提供了强大而高效的工具,是构建复杂数据结构的基石。在下一篇文章中,我们将探讨集合类型的另一个重要成员——String,学习Rust中字符串处理的独特哲学和强大功能。

掌握Vector的使用,将使你能够优雅地处理各种动态数据场景,为构建高效的Rust应用程序奠定坚实基础。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐