讲解

复合类型把多个值组合成一个。Rust 内置两种:元组(tuple)和数组(array)。元组是长度固定、元素类型可以各不相同的组合:let tup: (i32, f64, &str) = (500, 6.4, "元组")。取值有两种方式:模式解构 let (x, y, z) = tup,或者点号加下标 tup.0。函数想返回多个值时,返回元组是最轻量的写法。空元组 () 叫单元类型,「没有有意义的返回值」的函数实际返回的就是它。

数组是长度固定、元素类型必须相同的序列,写在栈上:let a: [i32; 5] = [1, 2, 3, 4, 5],类型标注里 [i32; 5] 的分号后就是长度——长度是类型的一部分,[i32; 3] 和 [i32; 4] 是两个不同的类型。重复初始化有语法糖:let zeros = [0; 10] 得到十个 0。

数组长度编译期写死,这个限制在真实业务里很快会遇到天花板——元素个数要随运行变化时用 Vec(动态数组,第 16 章)。数组的主场是元素个数确实固定的场景:一周七天、RGBA 四通道、固定大小的缓冲区。下标访问 arr[i] 越界会 panic(编译期检查不了运行时下标),想要安全访问用 .get(i),越界时得到 None 而不是崩溃。

示例

元组的解构与下标访问:

fn main() {
    let tup: (i32, f64, &str) = (500, 6.4, "元组");

    let (x, y, z) = tup; // 解构
    println!("x={x}, y={y}, z={z}");
    println!("第一个元素是 {}", tup.0);

    // 函数用元组一次返回多个值
    fn min_max(a: i32, b: i32) -> (i32, i32) {
        if a < b { (a, b) } else { (b, a) }
    }
    let (lo, hi) = min_max(9, 3);
    assert_eq!((lo, hi), (3, 9));
}

数组的初始化、遍历与安全访问:

fn main() {
    let arr: [i32; 5] = [10, 20, 30, 40, 50];
    let same = [7; 3]; // [7, 7, 7]

    let mut sum = 0;
    for n in arr {
        sum += n;
    }
    assert_eq!(sum, 150);
    assert_eq!(same, [7, 7, 7]);

    // .get 越界返回 None,不 panic
    match arr.get(10) {
        Some(v) => println!("第 10 项是 {v}"),
        None => println!("下标 10 越界了(数组长度 {})", arr.len()),
    }
}

常见坑

  • arr[i] 越界 panic:下标来自运行时数据(用户输入、计算结果)时,用 .get(i) 拿到 Option 再处理,别让程序崩在用户手里。
  • 以为数组能变长:[i32; 5] 永远是 5 个元素,push/append 不存在;要变长请换 Vec。
  • 混淆 (x) 和 (x,):(5) 只是带括号的 5,单元素元组必须写 (5,)——这个逗号是语法的一部分。
  • 元组当结构体用:元素超过三四个、或需要给字段起名时,元组的可读性会崩,该上结构体(第 12 章)。

小结

元组:固定长度、类型可混合,解构或 .0 取值;数组:固定长度、类型统一,长度写进类型,.get() 是安全访问。需要变长请期待第 16 章的 Vec。下一章讲函数。