Rust - 数组
Rust - 数组(Arrays)、向量(Vectors)和切片(Slices)
Section titled “Rust - 数组(Arrays)、向量(Vectors)和切片(Slices)”在本章中,我们将学习 Rust 中用于数据序列的主要集合类型。我们将从简单、固定大小的集合类型数组开始,然后介绍更灵活和常用的类型:向量(vectors)和切片(slices)。
一个简单的变量一次只能容纳一个值。要存储值的列表,例如游戏中排名前 10 的分数,我们需要一个可以容纳多个值的数据结构。数组是实现此目的最基本的方式。
理解数组 [T; N]
Section titled “理解数组 [T; N]”Rust 中的数组是相同类型(T)的多个值的集合,具有固定长度(N)。
- 固定大小(Fixed Size):数组一旦声明,其大小就永远不能改变。这是它与向量等更灵活的类型之间的关键区别。
- 同质性(Homogeneous):数组中的所有元素都必须具有相同的数据类型。
- 栈分配(Stack Allocated):数组在栈上分配内存,这使得它们的访问速度非常快。当你在编译时就知道所需元素的精确数量时,这是理想的选择。
- 连续内存(Sequential Memory):数组的元素在内存中是连续存储的,这允许高效、可预测的访问。
- 索引访问(Indexed Access):元素通过其索引(从 0 开始)访问。
声明和初始化数组
Section titled “声明和初始化数组”以下是在 Rust 中声明和初始化数组的常见方式。
// Syntax 1: Type inference// The compiler infers the type and size.let my_array = [1, 2, 3, 4, 5];
// Syntax 2: Explicit type and size annotation// [type; size]let my_array_typed: [i32; 5] = [1, 2, 3, 4, 5];
// Syntax 3: Initialize all elements to the same value// [default_value; size]let all_zeros = [0; 10]; // Creates an array of 10 zeros.示例:基本数组用法
Section titled “示例:基本数组用法”此示例展示了如何创建数组、访问元素以及获取其长度。我们使用调试格式 {:?} 来打印整个数组。
fn main() { // Declare an array of 4 integers. let numbers: [i32; 4] = [10, 20, 30, 40];
// Print the entire array. println!("Array: {:?}", numbers);
// Get the length of the array. println!("Array size: {}", numbers.len());
// Access a single element by index. let first_element = numbers[0]; println!("The first element is: {}", first_element);}Array: [10, 20, 30, 40]Array size: 4The first element is: 10对数组中的每个元素执行操作是很常见的。符合 Rust 习惯的做法是为此使用迭代器(iterator),它比手动基于索引的循环更安全、更具表达力。
示例:使用迭代器
Section titled “示例:使用迭代器”.iter() 方法创建一个迭代器,允许你循环遍历每个元素。要同时获取索引和值,请使用 .enumerate()。
fn main() { let weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"];
println!("Iterating over values:"); for day in weekdays.iter() { println!("Day: {}", day); }
println!("\nIterating with index and value:"); for (index, day) in weekdays.iter().enumerate() { println!("Day {}: {}", index + 1, day); }}Iterating over values:Day: MondayDay: TuesdayDay: WednesdayDay: ThursdayDay: Friday
Iterating with index and value:Day 1: MondayDay 2: TuesdayDay 3: WednesdayDay 4: ThursdayDay 5: Friday默认情况下,Rust 中的变量是不可变的。要修改数组的元素,必须使用 mut 关键字声明它。
fn main() { let mut scores: [i32; 5] = [88, 92, 79, 100, 95]; println!("Original scores: {:?}", scores);
// Update the score at index 2 scores[2] = 85; println!("Updated scores: {:?}", scores);}Original scores: [88, 92, 79, 100, 95]Updated scores: [88, 92, 85, 100, 95]超越数组:向量和切片
Section titled “超越数组:向量和切片”数组很有用,但其固定大小限制了其用途。对于大多数实际场景,你将使用向量(Vectors)和切片(Slices)。
- 向量(
Vec<T>):一个可增长、可调整大小的列表。它存储在堆上。当你需要一个项目列表时,这是你最常用的类型。 - 切片(
&[T]):是对连续元素序列的“视图”或“引用”。切片允许你安全高效地访问数组或向量的一部分,而无需复制数据。它们对于编写灵活的函数非常强大。
使用切片实现灵活的函数
Section titled “使用切片实现灵活的函数”与其编写一个只接受特定大小数组(如 [i32; 3])的函数,不如接受一个切片(&[i32])。这使得你的函数更通用,因为它现在可以处理任何大小的数组,也可以处理向量。
// This function takes a slice of integers, making it very flexible.fn sum_slice(numbers: &[i32]) -> i32 { let mut total = 0; for &num in numbers { total += num; } total}
fn main() { let arr1: [i32; 5] = [1, 2, 3, 4, 5]; let arr2: [i32; 3] = [10, 20, 30]; let vec1: Vec<i32> = vec![100, 200, 300];
// We can pass a reference to the whole array, which is coerced into a slice. println!("Sum of arr1: {}", sum_slice(&arr1));
// Or a slice of a portion of the array. println!("Sum of part of arr1: {}", sum_slice(&arr1[1..4])); // Elements at index 1, 2, 3
// The same function works for arr2! println!("Sum of arr2: {}", sum_slice(&arr2));
// And it works for vectors too! println!("Sum of vec1: {}", sum_slice(&vec1));}Sum of arr1: 15Sum of part of arr1: 9Sum of arr2: 60Sum of vec1: 600常见陷阱和最佳实践
Section titled “常见陷阱和最佳实践”- 越界访问(Out-of-Bounds Access):使用不存在的索引访问数组会导致程序
panic。例如,对大小为 5 的数组访问numbers[10]。始终检查长度或使用迭代器来避免此问题。 - 选择正确的类型(Choosing the Right Type):当你确定元素数量不会改变并且需要栈性能时,使用数组
[T; N]。其他所有情况使用向量Vec<T>。在函数参数中使用切片&[T]以使其更灵活。 - 常数作为大小(Constants for Size):数组的大小必须在编译时已知。如果你需要为大小使用命名值,它必须是一个
const常量。
fn main() { const ARRAY_SIZE: usize = 20; // This is valid because ARRAY_SIZE is a constant. let my_array = [0; ARRAY_SIZE]; println!("Element 10 is {}", my_array[10]);}