返回文章列表

文章

Rust 中的 向量(Vec)、数组、Slice(切片)全面解析

目录
  1. 当然可以,下面是对 Rust 中的 Vec<T>、[T; N](数组)和 &[T](切片) 三者的系统性总结,涵盖它们的区别、相互转换方式和典型应用场景。
  2. 🧩 Rust 中的 Vec、数组、切片全面解析
  3. 🔢 一览表:三者核心区别对比
  4. 🧱 类型本质
  5. 数组 [T; N]
  6. 向量 Vec<T>
  7. 切片 &[T] 或 &mut [T]
  8. 🔁 三者之间的转换方式
  9. ⚠️ 注意:从切片或数组到 Vec 的转换会 复制数据,从 Vec 到切片则是 借用引用,效率更高。
  10. ✅ 函数参数中的最佳实践
  11. 这样函数就能同时接收数组和向量,更具通用性。
  12. 🧪 示例对比:访问与修改
  13. 🧠 使用建议总结
  14. 📌 小知识:Vec 解引用为切片
  15. 🔚 结语

当然可以,下面是对 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✅ 可调用 pushpop 等方法
存储位置栈(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 代码。