06-数组与索引表达式

数组与索引表达式 — The Rust Reference

译文 · 基于 The Rust Reference

原文链接: https://doc.rust-lang.org/reference/expressions/array-expr.html

r[expr.array]

数组与索引表达式

数组表达式

r[expr.array.syntax]

ArrayExpression -> `[` ArrayElements? `]`

ArrayElements ->
      Expression ( `,` Expression )* `,`?
    | Expression `;` Expression

r[expr.array.constructor] 数组表达式用于构造数组。数组表达式有两种形式。

r[expr.array.array] 第一种形式逐一列出数组中的每个值。

r[expr.array.array-syntax] 该形式的语法是:由方括号括起的、类型一致的、以逗号分隔的表达式列表。

r[expr.array.array-behavior] 这会生成一个数组,按书写顺序包含这些值。

r[expr.array.repeat] 第二种形式的语法是:由方括号括起的、以分号(;)分隔的两个表达式。

r[expr.array.repeat-operand] ; 之前的表达式称为重复操作数。

r[expr.array.length-operand] ; 之后的表达式称为长度操作数。

r[expr.array.length-restriction] 长度操作数必须是推断常量,或类型为 usize 的常量表达式(例如字面量或常量项)。

1
2
3
4
5
const C: usize = 1;
let _: [u8; C] = [0; 1]; // 字面量。
let _: [u8; C] = [0; C]; // 常量项。
let _: [u8; C] = [0; _]; // 推断常量。
let _: [u8; C] = [0; (((_)))]; // 推断常量。

注意 在数组表达式中,推断常量按[表达式][Expression]解析,但在语义上被当作一种单独的const 泛型实参。

r[expr.array.repeat-behavior] 该形式的数组表达式会创建一个长度为长度操作数值的数组,每个元素都是重复操作数的副本。也就是说,[a; b] 会创建一个包含 b 个 a 的值的副本的数组。

r[expr.array.repeat-copy] 若长度操作数的值大于 1,则要求重复操作数的类型实现 Copy,或为 const 块表达式,或为指向常量项的路径。

r[expr.array.repeat-const-item] 当重复操作数是 const 块或指向常量项的路径时,它会按长度操作数指定的次数求值。

r[expr.array.repeat-evaluation-zero] 若该值为 0,则完全不求值该 const 块或常量项。

r[expr.array.repeat-non-const] 对于既不是 const 块也不是指向常量项的路径的表达式,它只求值一次,然后将结果按长度操作数的值复制相应次数。

1
2
3
4
5
6
7
[1, 2, 3, 4];
["a", "b", "c", "d"];
[0; 128];              // 含 128 个零的数组
[0u8, 0u8, 0u8, 0u8,];
[[1, 0, 0], [0, 1, 0], [0, 0, 1]]; // 二维数组
const EMPTY: Vec<i32> = Vec::new();
[EMPTY; 2];

r[expr.array.index]

数组与切片索引表达式

r[expr.array.index.syntax]

IndexExpression -> Expression `[` Expression `]`

r[expr.array.index.array] 数组和切片类型的值可以通过在其后书写一个由方括号括起、类型为 usize 的表达式(即索引)来进行索引。当数组可变时,得到的内存位置可以被赋值。

r[expr.array.index.trait] 对其它类型,索引表达式 a[b] 等价于 *std::ops::Index::index(&a, b),或在可变位置表达式上下文中等价于 *std::ops::IndexMut::index_mut(&mut a, b),但有一个例外:当索引表达式发生临时值生命周期延长时,被索引表达式 a 的临时作用域也会被延长。与方法一样,Rust 也会对 a 反复插入解引用操作以查找实现。

1
2
3
4
// 保存 `vec![()]` 结果的临时值会被延长
// 到块的末尾,因此 `x` 可在后续语句中使用。
let x = &vec![()][0];
## x;
1
2
3
4
// 保存 `vec![()]` 结果的临时值会在语句末尾被丢弃,
// 因此之后使用 `y` 是错误的。
let y = &*std::ops::Index::index(&vec![()], 0); // 错误
## y;

r[expr.array.index.zero-index] 数组和切片的索引从零开始。

r[expr.array.index.const] 数组访问是常量表达式,因此在索引值为常量时可以在编译期检查边界。否则会在运行时执行检查,失败时会使线程进入 panic 状态。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// 该 lint 默认是否认级别。
#![warn(unconditional_panic)]

([1, 2, 3, 4])[2];        // 求值为 3

let b = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
b[1][2];                  // 多维数组索引

let x = (["a", "b"])[10]; // 警告:索引越界

let n = 10;
let y = (["a", "b"])[n];  // 会 panic

let arr = ["a", "b"];
arr[10];                  // 警告:索引越界

r[expr.array.index.trait-impl] 通过实现 Index 和 IndexMut trait,也可以为数组和切片以外的类型实现数组索引表达式。

最后修改 August 21, 2026: 更新 (76fc81a2e)