文章
Rust 中的 向量(Vec)、数组、Slice(切片)全面解析
目录
当然可以,下面是对 Rust 中的 Vec<T>、[T; N](数组)和 &[T](切片) 三者的系统性总结,涵盖它们的区别、相互转换方式和典型应用场景。#
🧩 Rust 中的 Vec、数组、切片全面解析#
Rust 提供了多种用于存储同一类型元素的集合类型,其中最常用的三种是:
- 数组:
[T; N] - 切片:
&[T]或&mut [T] - 向量(Vec):
Vec<T>这三者虽然结构相似,但在用途、内存分配方式、可变性等方面有显著差异。
🔢 一览表:三者核心区别对比#
| 特性 | 数组 [T; N] | 切片 &[T] / &mut [T] | 向量 Vec<T> |
|---|---|---|---|
| 长度是否固定 | ✅ 编译期固定 | ✅ 运行时固定 | ❌ 可变,动态增加/删除元素 |
| 是否可变 | ✅/❌ 视变量定义而定 | ✅/❌ 视引用是否为 &mut | ✅ 可调用 push、pop 等方法 |
| 存储位置 | 栈(stack) | 栈中保存引用,数据可在栈或堆上 | 堆(heap) |
| 拥有权 | 拥有数据本身 | 只持有数据的引用 | 拥有数据 |
| 所需内存是否已知 | ✅ 编译时已知 | ❌ 运行时由切片指针+长度描述 | ❌ 动态分配 |
| 示例定义 | [1, 2, 3] | &[1, 2, 3] 或 &a[..] | vec![1, 2, 3] 或 Vec::new() |
| 常见用途 | 小型静态数组 | 泛型函数参数、处理部分数据 | 需要动态增长的列表数据结构 |
🧱 类型本质#
数组 [T; N]#
- 长度是类型的一部分(例如
[i32; 3]与[i32; 4]是完全不同的类型)。 - 存储在栈上,因为大小在编译期已知。
- 快速、无堆分配,适合性能敏感的代码。
向量 Vec<T>#
- 是 Rust 中的动态数组,数据存储在堆上。
- 长度在运行时确定,可以动态扩容。
- 拥有堆内存所有权,适用于需要传递、返回、存储的场景。
切片 &[T] 或 &mut [T]#
- 是对数组或向量的一段连续元素的只读或可写视图。
- 没有所有权,长度在运行期描述。
- 适用于函数参数、遍历和局部处理,不拷贝数据,效率高。
🔁 三者之间的转换方式#
| 从... | 转为... | 示例代码 |
|---|---|---|
[T; N] | &[T] | let s = &arr; 或 &arr[..] |
[T; N] | Vec<T> | let v = arr.to_vec(); |
Vec<T> | &[T] | let s = &vec; 或 vec.as_slice() |
&[T] | Vec<T>(复制) | let v = slice.to_vec(); |
⚠️ 注意:从切片或数组到 Vec 的转换会 复制数据,从 Vec 到切片则是 借用引用,效率更高。#
✅ 函数参数中的最佳实践#
当你要写一个函数处理一段数据,不论来源是数组还是向量时,建议使用**切片 **&[T] 作为参数类型:
fn sum(data: &[i32]) -> i32 {
data.iter().sum()
}
fn main() {
let arr = [1, 2, 3];
let vec = vec![4, 5, 6];
println!("{}", sum(&arr)); // 数组 → 切片
println!("{}", sum(&vec)); // Vec → 切片
}
这样函数就能同时接收数组和向量,更具通用性。#
🧪 示例对比:访问与修改#
fn main() {
let arr = [10, 20, 30]; // 数组
let vec = vec![10, 20, 30]; // 向量
let slice = &vec[..]; // 切片
println!("arr[0] = {}", arr[0]);
println!("vec[1] = {}", vec[1]);
println!("slice[2] = {}", slice[2]);
// vec 是可变的
let mut vec2 = vec![1, 2];
vec2.push(3);
println!("{:?}", vec2);
// arr.push(4); ❌ 错误:数组不可扩展
}
🧠 使用建议总结#
| 场景 | 推荐使用 |
|---|---|
| 数据长度在编译期固定 | [T; N] 数组 |
| 高性能场景、内联结构体字段 | [T; N] 数组 |
| 动态构建、增删元素、数据返回 | Vec<T> |
| 通用函数参数、遍历部分数据、避免拷贝 | &[T] 切片 |
📌 小知识:Vec 解引用为切片#
Vec<T> 实现了 Deref<Target = [T]>,可以自动转换为切片。例如:
let v = vec![1, 2, 3];
let s: &[i32] = &v; // 自动转换
let first = s[0];
甚至你可以比较数组和 Vec 的内容:
let a = [1, 2, 3];
let v = vec![1, 2, 3];
assert_eq!(a, *v); // Vec 解引用为 [T],与数组比较
🔚 结语#
Rust 的数组、向量和切片分别适用于不同的使用场景:
- 用数组管理静态固定大小数据
- 用切片在性能敏感或泛型函数中传参
- 用向量实现动态结构、返回值、内存管理 掌握它们的特性和转换方式,有助于你编写更高效、更 idiomatic 的 Rust 代码。