Rust集合类型(上):Vector的动态数组
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需要增长时,它会:
- 分配新的更大的内存块
- 将现有元素复制到新位置
- 释放旧的内存块
- 更新指针和容量
高级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中最常用且最灵活的集合类型,通过本文的学习,你应该已经掌握了:
- Vector的基本概念:动态数组的特性和优势
- 创建和初始化:多种创建Vector的方法
- 元素操作:添加、删除、访问和修改元素
- 迭代和搜索:多种迭代方式和搜索算法
- 排序和过滤:数据整理和筛选技术
- 性能优化:容量管理和避免不必要的开销
- 实际应用:在真实项目中使用Vector
- 内存管理:理解Vector的内部机制
Vector为处理动态数据序列提供了强大而高效的工具,是构建复杂数据结构的基石。在下一篇文章中,我们将探讨集合类型的另一个重要成员——String,学习Rust中字符串处理的独特哲学和强大功能。
掌握Vector的使用,将使你能够优雅地处理各种动态数据场景,为构建高效的Rust应用程序奠定坚实基础。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)