数组和切片

数组是一种存储在连续内存中的相同类型 T 的对象集合。 数组使用方括号 [] 创建,其长度在编译时已知, 是其类型签名 [T; length] 的一部分。

切片类似于数组,但其长度在编译时未知。切片是一个双字对象: 第一个字是指向数据的指针,第二个字是切片的长度。字的大小与 usize 相同, 由处理器架构决定,例如在 x86-64 上是 64 位。切片可用于借用数组的一部分, 其类型签名为 &[T]

use std::mem;

// 此函数借用一个切片。
fn analyze_slice(slice: &[i32]) {
    println!("切片的第一个元素:{}", slice[0]);
    println!("切片有 {} 个元素", slice.len());
}

fn main() {
    // 固定大小的数组(类型签名是多余的)。
    let xs: [i32; 5] = [1, 2, 3, 4, 5];

    // 所有元素可以初始化为相同的值。
    let ys: [i32; 500] = [0; 500];

    // 索引从 0 开始。
    println!("数组的第一个元素:{}", xs[0]);
    println!("数组的第二个元素:{}", xs[1]);

    // `len` 返回数组中元素的数量。
    println!("数组中的元素数量:{}", xs.len());

    // 数组是栈分配的。
    println!("数组占用 {} 字节", mem::size_of_val(&xs));

    // 数组可以自动借用为切片。
    println!("将整个数组借用为切片。");
    analyze_slice(&xs);

    // 切片可以指向数组的一部分。
    // 它们的形式是 [起始索引..结束索引]。
    // `起始索引` 是切片中的第一个位置。
    // `结束索引` 是切片中最后一个位置的后一个位置。
    println!("借用数组的一部分作为切片。");
    analyze_slice(&ys[1 .. 4]);

    // 空切片 `&[]` 的示例:
    let empty_array: [u32; 0] = [];
    assert_eq!(&empty_array, &[]);
    assert_eq!(&empty_array, &[][..]); // 同样的操作,但更详细

    // 可以使用 `.get` 安全地访问数组,它返回一个 `Option`。
    // 可以像下面这样对其进行匹配,或者使用 `.expect()`。
    // 如果你希望程序在访问越界时优雅地退出而不是继续执行,
    // 可以使用 `.expect()`。
    for i in 0..xs.len() + 1 { // 糟糕,访问超出了数组范围!
        match xs.get(i) {
            Some(xval) => println!("{}: {}", i, xval),
            None => println!("慢着!{} 超出范围了!", i),
        }
    }

    // Out of bound indexing on array with constant value causes compile time error.
    //println!("{}", xs[5]);
    // Out of bound indexing on slice causes runtime error.
    //println!("{}", xs[..][5]);
}