Skip to content

向量(vector)

本质是可变数组

  • 是一个 struct,定义在标准库中
  • vector 只能储存相同类型的值
  • 和数组一样,是整体所有权
  • vector 离开作用域时,其中的所有元素都会被释放
rust
pub struct Vec<T> {
    ptr: Unique<T>, // 指向堆内存的原始指针
    cap: usize,     // 容量
    len: usize,     // 当前长度
}

新建 vector

rust
// Vec::new 函数
let v: Vec<i32> = Vec::new();   // 空向量

// Vec::from 函数
let v: Vec<i32> = Vec::from([1, 2, 3]);

// vec! 宏
let v = vec![1, 2, 3];

Vec::new() 需要显式类型标注; Vec::from 函数和 vec! 宏可自动推导类型

增加元素

  • 使用 push() 方法添加元素到末尾
rust
let mut v = vec![1, 2, 3, 4, 5]; // 必须声明 mut
v.push(6);

push() 方法会获得 vector 的可变引用,vector 必须声明为 mut

读取元素

  • 使用 [] 直接索引读取元素
  • 使用 get() 方法读取元素

区别: [] 越界会 panic;get() 越界返回 None

rust
let v = vec![1, 2, 3, 4, 5];

// 使用索引 []
let third: &i32 = &v[2];
println!("The third element is {third}");

// 使用 get() 方法,返回 Option<&T>
let third: Option<&i32> = v.get(2);
match third {
    Some(third) => println!("The third element is {third}"),
    None => println!("There is no third element."),
}

get() 不会获得所有权,只返回不可变引用

遍历 vector 中的元素

  • 使用 for 循环遍历不可变引用
rust
let v = vec![100, 32, 57];

// 遍历不可变引用
for i in &v {
    println!("{i}");
}
  • 使用 for 循环遍历可变引用修改元素
rust
let mut v = vec![100, 32, 57];

// 遍历可变引用,修改元素
for i in &mut v {
    *i += 50;
}
  • 使用迭代器方法进行功能式编程
rust
let v = vec![100, 32, 57];

// 使用迭代器方法(获得所有权,v 被移动)
for i in v {
    println!("{i}");
}

遍历时使用 &v 借用不可变引用;使用 &mut v 借用可变引用;直接使用 v 会获得所有权

使用枚举来储存多种类型

  • vector 只能储存相同类型的值
  • 枚举本身就是一个类型,可以在 vector 中储存多种类型的数据
rust
enum SpreadsheetCell {
    Int(i32),
    Float(f64),
    Text(String),
}

let row = vec![
    SpreadsheetCell::Int(3),
    SpreadsheetCell::Text(String::from("blue")),
    SpreadsheetCell::Float(10.12),
];

// 遍历枚举 vector
for cell in &row {
    match cell {
        SpreadsheetCell::Int(i) => println!("Int: {i}"),
        SpreadsheetCell::Float(f) => println!("Float: {f}"),
        SpreadsheetCell::Text(s) => println!("Text: {s}"),
    }
}

vector 本身类型统一为 Vec<SpreadsheetCell>;访问具体值时需用 matchif let 模式匹配

常用方法

增删方法

rust
let mut v = vec![3, 1, 4, 1, 5, 9];

v.pop();              // 移除并返回最后一个元素 → Option<T>(获得所有权)
v.remove(0);          // 移除索引 0 的元素(后续元素左移),返回该元素(获得所有权)
v.insert(1, 10);      // 在索引 1 处插入 10(原有元素右移)
v.drain(0..2);        // 移除索引 0..2 的元素,返回被移除元素的迭代器(获得所有权)
v.retain(|x| *x > 2); // 只保留满足条件的元素(原地过滤)
v.dedup();            // 去除相邻重复元素(配合 sort 可实现完全去重)
v.clear();            // 清空向量

查询方法

rust
let v = vec![1, 2, 3, 4, 5];

v.len();              // 返回元素个数 → usize
v.is_empty();         // 返回是否为空 → bool
v.contains(&3);       // 返回是否包含某值 → bool(借用不可变引用)
v.iter().position(|x| *x == 3); // 返回首个满足条件的索引 → Option<usize>(借用不可变引用)
v.first();            // 返回首个元素 → Option<&T>(借用不可变引用)
v.last();             // 返回最后一个元素 → Option<&T>(借用不可变引用)

排序

rust
let mut v = vec![3, 1, 4, 1, 5];
v.sort();                         // 对实现了 Ord 的类型排序(整数、字符串等)
v.sort_by(|a, b| b.cmp(a));       // 自定义排序(这里是降序)
v.sort_by_key(|k| std::cmp::Reverse(*k)); // 按 key 排序

let mut floats = vec![3.1f64, 1.4, 2.7];
floats.sort_by(|a, b| a.partial_cmp(b).unwrap()); // f64 没实现 Ord,需用 partial_cmp

合并与扩展

rust
let mut a = vec![1, 2, 3];
let b = vec![4, 5, 6];
a.extend(b.iter());      // 追加 b 的元素到 a(借用 b 的不可变引用)
a.extend([7, 8, 9]);     // 追加数组
a.append(&mut b);        // 将 b 的所有元素移动到 a,b 变为空向量(获得 b 的可变引用)

容量与预分配

rust
// Vec::with_capacity 预先分配空间,避免频繁扩容,适合已知元素数量时
let mut v: Vec<i32> = Vec::with_capacity(100);
v.push(1);
println!("len={}, capacity={}", v.len(), v.capacity()); // len=1, capacity=100

v.shrink_to_fit();     // 释放多余容量,仅保留必需空间

基于 MIT 协议发布