4、复合数据类型:元组与数组

好,咱们今天聊聊 Rust 里的复合数据类型。说白了,就是把多个值打包在一起。Rust 提供了两种最基本的方式:元组和数组。这两种东西看着像,但用起来差别挺大的。

4.1 元组(Tuple)的定义与解构

元组,你可以把它想象成一个「小包裹」。里面可以装不同类型的东西。比如一个整数、一个浮点数、一个布尔值,全塞进去没问题。

let person: (i32, f64, bool) = (25, 1.75, true);

我个人习惯用元组来返回多个值。比如写一个函数,既要返回计算结果,又要返回状态码,元组就特别顺手。

访问元组元素,有两种方式:

  1. 点号索引person.0person.1person.2
  2. 解构:把元组拆开,赋值给多个变量
let (age, height, is_student) = person;
println!("年龄:{},身高:{},是否学生:{}", age, height, is_student);

解构这个特性,我在项目中经常用来简化代码。比如从数据库查出一条记录,直接解构成几个变量,比一个个取索引清爽多了。

小技巧:如果你只需要元组里的某几个值,可以用 _ 忽略不需要的部分。
比如 let (age, _, _) = person;,只取年龄,剩下的不要了。

4.2 数组(Array)的定义与访问

数组和元组最大的区别是:数组里所有元素类型必须相同。而且数组的长度是固定的,编译时就确定了。

let numbers: [i32; 5] = [1, 2, 3, 4, 5];

这里 [i32; 5] 表示「5 个 i32 类型的元素」。你还可以用简写方式:

let zeros = [0; 10];  // 创建 10 个 0,等价于 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

访问数组元素用方括号索引:

let first = numbers[0];  // 1
let third = numbers[2];  // 3

嗯,这里要注意:数组索引从 0 开始,这个和大多数语言一样。

4.3 数组越界的运行时行为

这是 Rust 一个非常硬核的地方。你想想看,在 C 语言里数组越界了,程序可能继续跑,但数据已经乱了。Rust 不跟你玩这套。

重要警告:Rust 会在运行时检查数组索引是否越界。一旦越界,程序会立即 panic(崩溃),不会给你任何「侥幸」的机会。
let arr = [10, 20, 30];
let index = 5;
println!("{}", arr[index]);  // 运行时 panic!

我曾经在写一个网络协议解析器时,因为没仔细检查数据包长度,导致数组越界。Rust 直接 panic 了。当时觉得「这也太严格了吧」,但事后想想,这比数据被静默破坏要好一万倍。

为什么会这样?因为 Rust 的设计哲学是:宁可程序崩溃,也不让未定义行为发生。数组越界在 C/C++ 里是未定义行为,可能引发安全漏洞。Rust 直接把它掐死在摇篮里。

如果你不确定索引是否安全,可以用 get 方法:

match arr.get(5) {
    Some(value) => println!("找到了:{}", value),
    None => println!("索引越界了,但程序没崩溃"),
}

这样就不会 panic 了,而是返回一个 Option 类型,让你自己决定怎么处理。

4.4 元组 vs 数组:一张表说清楚

特性 元组 (Tuple) 数组 (Array)
元素类型 可以不同 必须相同
长度 固定,编译时确定 固定,编译时确定
访问方式 tuple.0tuple.1 arr[0]arr[1]
解构 支持 不支持(但可以用模式匹配)
越界检查 不适用(索引固定) 运行时检查,越界则 panic
典型用途 返回多个值、临时打包 固定大小的数据集合

4.5 本章知识结构图

下面这张图帮你理清元组和数组的核心脉络:

复合数据类型:元组与数组 元组 (Tuple) 特点: • 元素类型可以不同 • 长度固定,编译时确定 • 用点号索引:tuple.0 解构示例: let (a, b, c) = tuple; 典型用途: • 函数返回多个值 • 临时数据打包 数组 (Array) 特点: • 元素类型必须相同 • 长度固定,编译时确定 • 用方括号索引:arr[0] 越界行为: 运行时 panic! 安全访问: arr.get(index) → Option • 固定大小数据集合 vs

说白了,元组和数组都是「打包」数据的方式,但适用场景不同。元组灵活,可以混装不同类型;数组规整,适合批量处理相同类型的数据。而 Rust 对数组越界的零容忍态度,正是它内存安全承诺的体现。

核心要点
• 元组用 . 访问,数组用 [] 访问
• 元组支持解构,数组不支持
• 数组越界会 panic,用 get() 可以安全访问
• 两种类型长度都在编译时固定,没有动态增长的版本(那是 Vec 的事)

公众号:蓝海资料掘金营,微信deep3321