引言

数组是编程中最基础的数据结构之一。在Rust中,数组(array)是一个固定大小的、同类型的元素集合,所有元素存储在栈上,具有零成本抽象的优势。理解数组对于掌握Rust的类型系统和内存管理至关重要。

本文将深入探讨Rust数组的所有方面,包括:

  • 数组的基础概念和特性
  • 数组的创建和初始化方式
  • 数组元素的访问和修改
  • 数组与切片的关系
  • 数组的常用操作方法
  • 多维数组的使用
  • 数组与其他集合类型的对比
  • 性能考虑和最佳实践

通过本文的学习,你将能够:

  • 熟练创建和使用数组
  • 理解数组的内存布局
  • 掌握数组的各种操作方法
  • 理解数组与切片、向量的区别
  • 在实际项目中正确选择数组

1. 数组基础

1.1 什么是数组?

数组是一个固定大小的、同类型的元素集合,所有元素连续存储在内存中:

fn main() {
    // 定义一个数组
    let arr: [i32; 5] = [1, 2, 3, 4, 5];
    
    println!("数组: {:?}", arr);
    println!("数组大小: {} 字节", std::mem::size_of::<[i32; 5]>());
}

在这里插入图片描述

数组的关键特性

  • 固定大小:创建时大小确定,不能改变
  • 同类型元素:所有元素必须是相同类型
  • 栈分配:数组存储在栈上(小数组)
  • 连续内存:元素在内存中连续存储
  • 编译时大小:大小必须在编译时确定

1.2 数组类型语法

数组类型的语法:[类型; 长度]

fn main() {
    // 类型注解示例
    let arr1: [i32; 5] = [1, 2, 3, 4, 5];      // 5个i32
    let arr2: [f64; 3] = [1.0, 2.0, 3.0];      // 3个f64
    let arr3: [char; 4] = ['a', 'b', 'c', 'd']; // 4个char
    let arr4: [bool; 2] = [true, false];       // 2个bool
    let arr5: [&str; 3] = ["a", "b", "c"];     // 3个&str
    
    println!("{:?}", arr1);
    println!("{:?}", arr2);
}

在这里插入图片描述

2. 数组的创建方式

2.1 显式初始化

fn main() {
    // 方式1:指定每个元素
    let arr1 = [1, 2, 3, 4, 5];
    
    // 方式2:指定类型和元素
    let arr2: [i32; 5] = [10, 20, 30, 40, 50];
    
    // 方式3:混合类型(会统一为相同类型)
    let arr3 = [1, 2, 3];  // 类型推断为 [i32; 3]
    
    println!("{:?}", arr1);
    println!("{:?}", arr2);
    println!("{:?}", arr3);
}

在这里插入图片描述

2.2 相同值初始化

使用 [值; 长度] 语法创建所有元素相同的数组:

fn main() {
    // 创建5个0
    let zeros: [i32; 5] = [0; 5];
    println!("{:?}", zeros);  // [0, 0, 0, 0, 0]
    
    // 创建10个true
    let bools = [true; 10];
    println!("{:?}", bools);
    
    // 创建3个字符串
    let strings = ["hello"; 3];
    println!("{:?}", strings);  // ["hello", "hello", "hello"]
    
    // 创建浮点数数组
    let floats = [3.14; 5];
    println!("{:?}", floats);
}

在这里插入图片描述

2.3 从向量转换

fn main() {
    let vec = vec![1, 2, 3, 4, 5];
    
    // 将向量转为数组(需要明确大小)
    // 注意:长度必须匹配,否则编译错误
    // let arr: [i32; 5] = vec.try_into().unwrap();
    
    // 或者使用数组切片
    let slice: &[i32] = &vec;
    
    println!("{:?}", slice);
}

在这里插入图片描述

2.4 数组字面量

fn main() {
    // 空数组(长度0)
    let empty: [i32; 0] = [];
    println!("空数组长度: {}", empty.len());
    
    // 单元素数组
    let single = [42];
    println!("单元素数组: {:?}", single);
    
    // 大数组(使用相同值)
    let large = [0; 1000];
    println!("大数组长度: {}", large.len());
}

3. 数组元素的访问

3.1 索引访问

使用方括号 [] 和索引访问数组元素:

fn main() {
    let arr = [10, 20, 30, 40, 50];
    
    // 访问单个元素
    println!("第一个元素: {}", arr[0]);  // 10
    println!("第三个元素: {}", arr[2]);  // 30
    println!("最后一个元素: {}", arr[4]); // 50
    
    // 修改元素(需要mut)
    let mut arr2 = [1, 2, 3, 4, 5];
    arr2[0] = 100;
    println!("修改后: {:?}", arr2);  // [100, 2, 3, 4, 5]
}

3.2 越界检查

Rust在运行时检查数组越界:

fn main() {
    let arr = [1, 2, 3, 4, 5];
    
    // 编译时无法检查,运行时panic
    // println!("{}", arr[10]);  // panic! index out of bounds
    
    // 安全访问:使用get方法
    match arr.get(10) {
        Some(value) => println!("值: {}", value),
        None => println!("索引超出范围"),
    }
    
    // 或者使用get配合unwrap_or
    let value = arr.get(10).unwrap_or(&0);
    println!("值: {}", value);  // 0(默认值)
}

3.3 安全的索引访问

fn main() {
    let arr = [10, 20, 30, 40, 50];
    
    // 方式1:使用get方法(返回Option)
    if let Some(val) = arr.get(2) {
        println!("索引2的值: {}", val);
    }
    
    // 方式2:先检查长度
    let index = 3;
    if index < arr.len() {
        println!("索引{}的值: {}", index, arr[index]);
    }
    
    // 方式3:使用unwrap_or
    let value = arr.get(100).unwrap_or(&-1);
    println!("值: {}", value);
}

4. 数组的基本操作

4.1 获取数组长度

fn main() {
    let arr = [1, 2, 3, 4, 5];
    
    // 使用len()方法
    println!("数组长度: {}", arr.len());
    
    // 使用数组大小
    println!("数组大小: {} 字节", std::mem::size_of_val(&arr));
    
    // 计算元素大小
    let element_size = std::mem::size_of::<i32>();
    let array_size = arr.len() * element_size;
    println!("元素大小: {} 字节", element_size);
    println!("总大小: {} 字节", array_size);
}

4.2 数组迭代

fn main() {
    let arr = [10, 20, 30, 40, 50];
    
    // 方式1:使用for循环和引用
    for element in &arr {
        println!("{}", element);
    }
    
    // 方式2:使用iter()方法
    for element in arr.iter() {
        println!("{}", element);
    }
    
    // 方式3:获取索引和值
    for (index, value) in arr.iter().enumerate() {
        println!("索引 {}: 值 {}", index, value);
    }
    
    // 方式4:可变迭代
    let mut arr2 = [1, 2, 3, 4, 5];
    for element in arr2.iter_mut() {
        *element *= 2;
    }
    println!("翻倍后: {:?}", arr2);  // [2, 4, 6, 8, 10]
}

4.3 数组切片

数组可以创建切片(slice):

fn main() {
    let arr = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
    
    // 创建切片
    let slice1 = &arr[0..5];      // 索引0到4
    let slice2 = &arr[2..7];      // 索引2到6
    let slice3 = &arr[..5];       // 从开始到索引4
    let slice4 = &arr[5..];       // 从索引5到最后
    let slice5 = &arr[..];        // 整个数组的切片
    
    println!("切片1: {:?}", slice1);  // [10, 20, 30, 40, 50]
    println!("切片2: {:?}", slice2);  // [30, 40, 50, 60, 70]
    println!("切片3: {:?}", slice3);  // [10, 20, 30, 40, 50]
    println!("切片4: {:?}", slice4);  // [60, 70, 80, 90, 100]
    println!("切片5: {:?}", slice5);  // 整个数组
}

5. 数组常用方法

5.1 数组查询方法

fn main() {
    let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    // 查找元素
    if let Some(pos) = arr.iter().position(|&x| x == 5) {
        println!("5在索引: {}", pos);
    }
    
    // 检查包含
    println!("包含5: {}", arr.contains(&5));
    
    // 查找第一个满足条件的元素
    if let Some(val) = arr.iter().find(|&&x| x > 5) {
        println!("第一个大于5的数: {}", val);
    }
    
    // 查找最后一个满足条件的元素
    if let Some(val) = arr.iter().rfind(|&&x| x < 5) {
        println!("最后一个小于5的数: {}", val);
    }
}

5.2 数组统计方法

fn main() {
    let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    // 求和
    let sum: i32 = arr.iter().sum();
    println!("和: {}", sum);  // 55
    
    // 求积
    let product: i32 = arr.iter().product();
    println!("积: {}", product);  // 3628800
    
    // 求最大值
    if let Some(max) = arr.iter().max() {
        println!("最大值: {}", max);  // 10
    }
    
    // 求最小值
    if let Some(min) = arr.iter().min() {
        println!("最小值: {}", min);  // 1
    }
    
    // 求平均值
    let avg = sum as f64 / arr.len() as f64;
    println!("平均值: {:.2}", avg);  // 5.50
}

5.3 数组转换方法

fn main() {
    let arr = [1, 2, 3, 4, 5];
    
    // 映射到新数组(会创建新数组)
    let doubled: Vec<i32> = arr.iter().map(|x| x * 2).collect();
    println!("翻倍: {:?}", doubled);
    
    // 过滤
    let evens: Vec<i32> = arr.iter().filter(|&&x| x % 2 == 0).copied().collect();
    println!("偶数: {:?}", evens);
    
    // 过滤和映射结合
    let result: Vec<i32> = arr.iter()
                             .filter(|&&x| x > 2)
                             .map(|x| x * x)
                             .collect();
    println!("过滤和平方: {:?}", result);  // [9, 16, 25]
}

5.4 数组排序

fn main() {
    let mut arr = [5, 2, 8, 1, 9, 3];
    
    // 排序(升序)
    arr.sort();
    println!("升序: {:?}", arr);  // [1, 2, 3, 5, 8, 9]
    
    // 降序排序
    let mut arr2 = [5, 2, 8, 1, 9, 3];
    arr2.sort_by(|a, b| b.cmp(a));  // 或使用 arr2.sort(); arr2.reverse();
    println!("降序: {:?}", arr2);  // [9, 8, 5, 3, 2, 1]
    
    // 使用sort_by进行自定义排序
    let mut arr3 = [5, 2, 8, 1, 9, 3];
    arr3.sort_by(|a, b| (a % 2).cmp(&(b % 2)));  // 奇数在前
    println!("自定义排序: {:?}", arr3);
}

6. 多维数组

6.1 二维数组

fn main() {
    // 方式1:使用数组的数组
    let matrix: [[i32; 3]; 3] = [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
    ];
    
    // 访问元素
    println!("matrix[0][0] = {}", matrix[0][0]);  // 1
    println!("matrix[1][2] = {}", matrix[1][2]);  // 6
    
    // 遍历二维数组
    for (i, row) in matrix.iter().enumerate() {
        for (j, &value) in row.iter().enumerate() {
            println!("matrix[{}][{}] = {}", i, j, value);
        }
    }
    
    // 打印矩阵
    for row in matrix.iter() {
        println!("{:?}", row);
    }
}

6.2 二维数组的创建和初始化

fn main() {
    // 创建全零矩阵
    let zeros: [[i32; 3]; 3] = [[0; 3]; 3];
    println!("零矩阵:");
    for row in zeros.iter() {
        println!("{:?}", row);
    }
    
    // 创建单位矩阵
    let mut identity = [[0; 3]; 3];
    for i in 0..3 {
        identity[i][i] = 1;
    }
    println!("\n单位矩阵:");
    for row in identity.iter() {
        println!("{:?}", row);
    }
    
    // 创建随机矩阵(示例)
    let matrix = [
        [1, 2],
        [3, 4],
        [5, 6],
    ];
    println!("\n矩阵:");
    for row in matrix.iter() {
        println!("{:?}", row);
    }
}

6.3 矩阵运算示例

fn main() {
    // 矩阵加法
    fn add_matrices(a: [[i32; 3]; 3], b: [[i32; 3]; 3]) -> [[i32; 3]; 3] {
        let mut result = [[0; 3]; 3];
        for i in 0..3 {
            for j in 0..3 {
                result[i][j] = a[i][j] + b[i][j];
            }
        }
        result
    }
    
    let a = [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
    ];
    
    let b = [
        [9, 8, 7],
        [6, 5, 4],
        [3, 2, 1],
    ];
    
    let sum = add_matrices(a, b);
    println!("矩阵和:");
    for row in sum.iter() {
        println!("{:?}", row);  // [10, 10, 10], [10, 10, 10], [10, 10, 10]
    }
    
    // 矩阵转置
    fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {
        let mut result = [[0; 3]; 3];
        for i in 0..3 {
            for j in 0..3 {
                result[j][i] = matrix[i][j];
            }
        }
        result
    }
    
    let transposed = transpose(a);
    println!("\n转置矩阵:");
    for row in transposed.iter() {
        println!("{:?}", row);
    }
}

7. 数组与其他集合类型的对比

7.1 数组 vs 向量(Vec)

特性 数组 [T; N] 向量 Vec<T>
大小 固定(编译时) 可变(运行时)
内存位置
性能 更快(无分配) 较慢(需要分配)
最大大小 受栈限制 受内存限制
使用场景 固定大小数据 动态大小数据
fn main() {
    // 数组:固定大小,栈分配
    let arr: [i32; 5] = [1, 2, 3, 4, 5];
    // arr.push(6);  // 错误!数组大小固定
    
    // 向量:可变大小,堆分配
    let mut vec = vec![1, 2, 3, 4, 5];
    vec.push(6);  // ✅ 可以添加元素
    println!("{:?}", vec);
    
    // 何时使用数组?
    // - 数据大小在编译时已知且固定
    // - 需要栈分配的性能优势
    // - 小的固定大小集合
    
    // 何时使用向量?
    // - 数据大小在运行时确定
    // - 需要动态添加/删除元素
    // - 大型数据集
}

7.2 数组 vs 切片(Slice)

fn main() {
    let arr = [1, 2, 3, 4, 5];
    
    // 数组:有固定大小
    println!("数组大小: {}", arr.len());
    
    // 切片:数组的视图,无所有权
    let slice: &[i32] = &arr[1..4];
    println!("切片: {:?}", slice);  // [2, 3, 4]
    println!("切片大小: {}", slice.len());
    
    // 切片可以来自数组或向量
    let vec = vec![1, 2, 3, 4, 5];
    let vec_slice: &[i32] = &vec[1..4];
    println!("向量切片: {:?}", vec_slice);
    
    // 函数通常接受切片而不是数组
    fn sum(slice: &[i32]) -> i32 {
        slice.iter().sum()
    }
    
    println!("数组和: {}", sum(&arr));
    println!("切片和: {}", sum(slice));
}

8. 数组的实用技巧

8.1 数组解构

fn main() {
    let arr = [1, 2, 3, 4, 5];
    
    // 解构数组
    let [first, second, third, fourth, fifth] = arr;
    println!("{} {} {} {} {}", first, second, third, fourth, fifth);
    
    // 部分解构
    let [first, .., last] = arr;
    println!("首: {}, 尾: {}", first, last);
    
    // 忽略某些元素
    let [a, _, _, _, e] = arr;
    println!("{} {}", a, e);
}

8.2 数组作为函数参数和返回值

// 数组作为参数
fn print_array(arr: &[i32; 5]) {
    for elem in arr.iter() {
        print!("{} ", elem);
    }
    println!();
}

// 数组作为返回值
fn create_array() -> [i32; 5] {
    [1, 2, 3, 4, 5]
}

// 接受任意大小的数组切片(更灵活)
fn process_array(arr: &[i32]) {
    println!("处理数组,长度: {}", arr.len());
}

fn main() {
    let arr = [10, 20, 30, 40, 50];
    print_array(&arr);
    
    let new_arr = create_array();
    print_array(&new_arr);
    
    process_array(&arr);
    process_array(&arr[1..4]);  // 也可以处理切片
}

8.3 数组填充技巧

fn main() {
    // 使用循环填充
    let mut arr = [0; 10];
    for i in 0..10 {
        arr[i] = i as i32;
    }
    println!("{:?}", arr);
    
    // 使用迭代器填充
    let arr2: [i32; 10] = (0..10).map(|x| x as i32)
                                 .collect::<Vec<i32>>()
                                 .try_into()
                                 .unwrap();
    println!("{:?}", arr2);
    
    // 使用enum填充
    #[derive(Debug)]
    enum Status {
        Active,
        Inactive,
        Pending,
    }
    
    let statuses = [Status::Active, Status::Inactive, Status::Pending];
    // 注意:enum也可以用在数组中
}

9. 数组性能考虑

9.1 栈大小限制

fn main() {
    // 小数组:栈分配,快速
    let small: [i32; 10] = [0; 10];
    println!("小数组大小: {} 字节", std::mem::size_of_val(&small));
    
    // 大数组:可能栈溢出
    // let large: [i32; 1_000_000] = [0; 1_000_000];  // 危险!
    // 大数组应该使用Vec或Box<[T]>
    
    // 安全的大数组(使用Box)
    let large: Box<[i32]> = vec![0; 1_000_000].into_boxed_slice();
    println!("大数组长度: {}", large.len());
}

9.2 数组 vs Vec 性能对比

fn main() {
    // 小数据集:数组更快
    let arr: [i32; 100] = [0; 100];
    
    // 大数据集:Vec更合适
    let vec = vec![0; 100_000];
    
    // 数组:零开销,栈分配
    // Vec:需要堆分配,但可以动态增长
    
    // 性能测试
    use std::time::Instant;
    
    let start = Instant::now();
    let _arr = [0; 1000];
    let duration = start.elapsed();
    println!("数组创建时间: {:?}", duration);
    
    let start = Instant::now();
    let _vec = vec![0; 1000];
    let duration = start.elapsed();
    println!("向量创建时间: {:?}", duration);
}

10. 实战示例

示例1:数组工具函数库

mod array_utils {
    // 查找数组中的最大值和最小值
    pub fn min_max(arr: &[i32]) -> Option<(i32, i32)> {
        if arr.is_empty() {
            return None;
        }
        let min = arr.iter().min().copied()?;
        let max = arr.iter().max().copied()?;
        Some((min, max))
    }
    
    // 数组求和
    pub fn sum(arr: &[i32]) -> i32 {
        arr.iter().sum()
    }
    
    // 数组平均值
    pub fn average(arr: &[i32]) -> Option<f64> {
        if arr.is_empty() {
            return None;
        }
        let sum: i32 = arr.iter().sum();
        Some(sum as f64 / arr.len() as f64)
    }
    
    // 数组反转(原地)
    pub fn reverse<T: Copy>(arr: &mut [T]) {
        let len = arr.len();
        for i in 0..len / 2 {
            arr.swap(i, len - 1 - i);
        }
    }
    
    // 查找元素索引
    pub fn find_index(arr: &[i32], target: i32) -> Option<usize> {
        arr.iter().position(|&x| x == target)
    }
}

fn main() {
    let arr = [10, 5, 8, 3, 15, 2];
    
    match array_utils::min_max(&arr) {
        Some((min, max)) => {
            println!("最小值: {}, 最大值: {}", min, max);
        }
        None => println!("数组为空"),
    }
    
    println!("和: {}", array_utils::sum(&arr));
    
    if let Some(avg) = array_utils::average(&arr) {
        println!("平均值: {:.2}", avg);
    }
    
    if let Some(index) = array_utils::find_index(&arr, 8) {
        println!("8在索引: {}", index);
    }
    
    let mut arr2 = [1, 2, 3, 4, 5];
    array_utils::reverse(&mut arr2);
    println!("反转后: {:?}", arr2);  // [5, 4, 3, 2, 1]
}

示例2:成绩管理系统

struct Student {
    name: String,
    scores: [f64; 5],  // 5门课程的成绩
}

impl Student {
    fn new(name: String, scores: [f64; 5]) -> Self {
        Self { name, scores }
    }
    
    fn average_score(&self) -> f64 {
        self.scores.iter().sum::<f64>() / self.scores.len() as f64
    }
    
    fn highest_score(&self) -> f64 {
        *self.scores.iter().max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap()
    }
    
    fn lowest_score(&self) -> f64 {
        *self.scores.iter().min_by(|a, b| a.partial_cmp(b).unwrap()).unwrap()
    }
    
    fn passed_all(&self) -> bool {
        self.scores.iter().all(|&score| score >= 60.0)
    }
}

fn main() {
    let student = Student::new(
        "Alice".to_string(),
        [85.0, 90.0, 78.0, 92.0, 88.0]
    );
    
    println!("学生: {}", student.name);
    println!("成绩: {:?}", student.scores);
    println!("平均分: {:.2}", student.average_score());
    println!("最高分: {:.2}", student.highest_score());
    println!("最低分: {:.2}", student.lowest_score());
    println!("全部及格: {}", student.passed_all());
}

示例3:矩阵运算库

mod matrix {
    pub type Matrix3x3 = [[f64; 3]; 3];
    
    pub fn create_zero() -> Matrix3x3 {
        [[0.0; 3]; 3]
    }
    
    pub fn create_identity() -> Matrix3x3 {
        let mut m = create_zero();
        for i in 0..3 {
            m[i][i] = 1.0;
        }
        m
    }
    
    pub fn add(a: Matrix3x3, b: Matrix3x3) -> Matrix3x3 {
        let mut result = create_zero();
        for i in 0..3 {
            for j in 0..3 {
                result[i][j] = a[i][j] + b[i][j];
            }
        }
        result
    }
    
    pub fn multiply(a: Matrix3x3, b: Matrix3x3) -> Matrix3x3 {
        let mut result = create_zero();
        for i in 0..3 {
            for j in 0..3 {
                for k in 0..3 {
                    result[i][j] += a[i][k] * b[k][j];
                }
            }
        }
        result
    }
    
    pub fn transpose(m: Matrix3x3) -> Matrix3x3 {
        let mut result = create_zero();
        for i in 0..3 {
            for j in 0..3 {
                result[j][i] = m[i][j];
            }
        }
        result
    }
    
    pub fn print(m: Matrix3x3) {
        for row in m.iter() {
            println!("{:?}", row);
        }
    }
}

fn main() {
    let a = [
        [1.0, 2.0, 3.0],
        [4.0, 5.0, 6.0],
        [7.0, 8.0, 9.0],
    ];
    
    let b = [
        [9.0, 8.0, 7.0],
        [6.0, 5.0, 4.0],
        [3.0, 2.0, 1.0],
    ];
    
    println!("矩阵A:");
    matrix::print(a);
    
    println!("\n矩阵B:");
    matrix::print(b);
    
    println!("\nA + B:");
    matrix::print(matrix::add(a, b));
    
    println!("\nA * B:");
    matrix::print(matrix::multiply(a, b));
    
    println!("\nA的转置:");
    matrix::print(matrix::transpose(a));
}

示例4:数据统计分析

fn analyze_data(data: &[i32]) {
    if data.is_empty() {
        println!("数据为空");
        return;
    }
    
    let sum: i32 = data.iter().sum();
    let count = data.len();
    let average = sum as f64 / count as f64;
    
    let max = *data.iter().max().unwrap();
    let min = *data.iter().min().unwrap();
    
    // 计算中位数
    let mut sorted = data.to_vec();
    sorted.sort();
    let median = if count % 2 == 0 {
        (sorted[count / 2 - 1] + sorted[count / 2]) as f64 / 2.0
    } else {
        sorted[count / 2] as f64
    };
    
    // 计算标准差
    let variance: f64 = data.iter()
        .map(|&x| (x as f64 - average).powi(2))
        .sum::<f64>() / count as f64;
    let std_dev = variance.sqrt();
    
    println!("=== 数据分析 ===");
    println!("数据: {:?}", data);
    println!("数量: {}", count);
    println!("和: {}", sum);
    println!("平均值: {:.2}", average);
    println!("最大值: {}", max);
    println!("最小值: {}", min);
    println!("中位数: {:.2}", median);
    println!("标准差: {:.2}", std_dev);
}

fn main() {
    let data = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
    analyze_data(&data);
    
    println!();
    
    let data2 = [5, 15, 25, 35, 45];
    analyze_data(&data2);
}

11. 常见错误与解决方案

错误1:数组大小不匹配

fn main() {
    // 错误:数组大小不匹配
    // let arr1: [i32; 5] = [1, 2, 3];  // 编译错误!
    
    // 解决1:匹配大小
    let arr1: [i32; 3] = [1, 2, 3];
    
    // 解决2:使用向量
    let vec1 = vec![1, 2, 3];
    
    // 解决3:使用切片(更灵活)
    fn process_data(data: &[i32]) {
        println!("处理 {} 个元素", data.len());
    }
    
    process_data(&arr1);
    process_data(&vec1);
}

错误2:越界访问

fn main() {
    let arr = [1, 2, 3, 4, 5];
    
    // 错误:越界访问
    // println!("{}", arr[10]);  // panic!
    
    // 解决:使用get方法
    match arr.get(10) {
        Some(val) => println!("值: {}", val),
        None => println!("索引超出范围"),
    }
    
    // 或先检查长度
    let index = 10;
    if index < arr.len() {
        println!("{}", arr[index]);
    } else {
        println!("索引 {} 超出范围", index);
    }
}

错误3:类型不匹配

fn main() {
    // 错误:类型不匹配
    // let arr: [i32; 3] = [1.0, 2.0, 3.0];  // f64 != i32
    
    // 解决:统一类型
    let arr1: [i32; 3] = [1, 2, 3];
    let arr2: [f64; 3] = [1.0, 2.0, 3.0];
    
    // 或转换类型
    let arr3: [i32; 3] = [1.0 as i32, 2.0 as i32, 3.0 as i32];
}

错误4:尝试修改不可变数组

fn main() {
    // 错误:尝试修改不可变数组
    // let arr = [1, 2, 3];
    // arr[0] = 10;  // 错误!
    
    // 解决:使用mut
    let mut arr = [1, 2, 3];
    arr[0] = 10;
    println!("{:?}", arr);  // [10, 2, 3]
}

12. 数组的高级用法

12.1 数组作为常量

const DAYS_IN_WEEK: [&str; 7] = [
    "Monday", "Tuesday", "Wednesday", "Thursday",
    "Friday", "Saturday", "Sunday"
];

const MONTHS: [&str; 12] = [
    "January", "February", "March", "April",
    "May", "June", "July", "August",
    "September", "October", "November", "December"
];

fn main() {
    println!("一周的第一天: {}", DAYS_IN_WEEK[0]);
    println!("一年有 {} 个月", MONTHS.len());
    
    for (i, day) in DAYS_IN_WEEK.iter().enumerate() {
        println!("第{}天: {}", i + 1, day);
    }
}

12.2 数组与模式匹配

fn analyze_array(arr: &[i32; 5]) {
    match arr {
        [a, b, c, d, e] if a == e => {
            println!("首尾相同: {}, {}, {}, {}, {}", a, b, c, d, e);
        }
        [a, _, _, _, e] if a > e => {
            println!("递减趋势");
        }
        [a, _, _, _, e] if a < e => {
            println!("递增趋势");
        }
        _ => {
            println!("其他模式");
        }
    }
}

fn main() {
    analyze_array(&[1, 2, 3, 4, 1]);  // 首尾相同
    analyze_array(&[10, 5, 3, 2, 1]);  // 递减趋势
    analyze_array(&[1, 2, 3, 4, 5]);   // 递增趋势
}

12.3 固定大小缓冲区

fn process_buffer(buffer: &mut [u8; 256]) {
    // 填充缓冲区
    for i in 0..256 {
        buffer[i] = (i % 256) as u8;
    }
    
    // 处理缓冲区
    let sum: u32 = buffer.iter().map(|&b| b as u32).sum();
    println!("缓冲区总和: {}", sum);
}

fn main() {
    let mut buffer = [0u8; 256];
    process_buffer(&mut buffer);
}

13. 扩展练习

练习1:数组工具函数

实现查找、反转、排序、去重等数组操作函数。

练习2:矩阵运算

实现完整的矩阵运算库(加法、乘法、转置、行列式)。

练习3:统计计算

实现计算数组的各种统计量(均值、方差、中位数、众数)。

练习4:数组搜索

实现线性搜索、二分搜索(需要排序)、查找所有匹配项。

练习5:数组转换

实现数组与向量、切片之间的转换函数。

14. 总结

核心要点回顾

  1. 数组特性:固定大小、同类型、栈分配、连续内存
  2. 创建方式:显式初始化、相同值初始化 [value; len]
  3. 元素访问:索引访问 arr[i]、安全访问 arr.get(i)
  4. 数组操作:迭代、切片、统计、转换
  5. 多维数组:数组的数组 [[T; N]; M]
  6. 性能考虑:栈大小限制、何时使用数组vs向量

关键特性

  • 固定大小:编译时确定,运行时不能改变
  • 栈分配:小数组性能优异
  • 类型安全:所有元素必须同类型
  • 零成本:无运行时开销

选择指南

场景 推荐 原因
固定大小的数据 数组 性能好,类型安全
编译时已知大小 数组 栈分配,速度快
动态大小数据 Vec 可以增长/缩小
大数组(>栈限制) Vec或Box<[T]> 避免栈溢出
函数参数 切片 &[T] 更灵活
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐