blob: e5505e3c8a9cfa6da8cc4d7473c6ca151c0862cd [file] [view] [edit]
r[expr.array]
# Array and array index expressions
## Array expressions
r[expr.array.syntax]
```grammar,expressions
ArrayExpression -> `[` ArrayElements? `]`
ArrayElements ->
Expression ( `,` Expression )* `,`?
| Expression `;` Expression
```
r[expr.array.constructor]
*Array expressions* construct [arrays][array]. Array expressions come in two forms.
r[expr.array.array]
The first form lists out every value in the array.
r[expr.array.array-syntax]
The syntax for this form is a comma-separated list of expressions of uniform type enclosed in square brackets.
r[expr.array.array-behavior]
This produces an array containing each of these values in the order they are written.
r[expr.array.repeat]
The syntax for the second form is two expressions separated by a semicolon (`;`) enclosed in square brackets.
r[expr.array.repeat-operand]
The expression before the `;` is called the *repeat operand*.
r[expr.array.length-operand]
The expression after the `;` is called the *length operand*.
r[expr.array.length-restriction]
The length operand must either be an [inferred const] or be a [constant expression] of type `usize` (e.g. a [literal] or a [constant item]).
```rust
const C: usize = 1;
let _: [u8; C] = [0; 1]; // Literal.
let _: [u8; C] = [0; C]; // Constant item.
let _: [u8; C] = [0; _]; // Inferred const.
let _: [u8; C] = [0; (((_)))]; // Inferred const.
```
> [!NOTE]
> In an array expression, an [inferred const] is parsed as an [expression][Expression] but then semantically treated as a separate kind of [const generic argument].
r[expr.array.repeat-behavior]
An array expression of this form creates an array with the length of the value of the length operand with each element being a copy of the repeat operand. That is, `[a; b]` creates an array containing `b` copies of the value of `a`.
r[expr.array.repeat-copy]
If the length operand has a value greater than 1 then this requires the repeat operand to have a type that implements [`Copy`], to be a [const block expression], or to be a [path] to a constant item.
r[expr.array.repeat-const-item]
When the repeat operand is a const block or a path to a constant item, it is evaluated the number of times specified in the length operand.
r[expr.array.repeat-evaluation-zero]
If that value is `0`, then the const block or constant item is not evaluated at all.
r[expr.array.repeat-non-const]
For expressions that are neither a const block nor a path to a constant item, it is evaluated exactly once, and then the result is copied the length operand's value times.
```rust
[1, 2, 3, 4];
["a", "b", "c", "d"];
[0; 128]; // array with 128 zeros
[0u8, 0u8, 0u8, 0u8,];
[[1, 0, 0], [0, 1, 0], [0, 0, 1]]; // 2D array
const EMPTY: Vec<i32> = Vec::new();
[EMPTY; 2];
```
r[expr.array.index]
## Array and slice indexing expressions
r[expr.array.index.syntax]
```grammar,expressions
IndexExpression -> Expression `[` Expression `]`
```
r[expr.array.index.autoderef]
The indexed operand `a` is automatically dereferenced as many times as necessary to find an array or slice type or a type that implements [`Index`] or [`IndexMut`], as the receiver of a method call is (see [expr.method.autoref-deref]). The following rules, and the rules on [place expressions], apply to the dereferenced operand.
r[expr.array.index.array]
An index expression `a[b]` where `a` has an [array] or [slice] type and `b` has type `usize` is built in and evaluates to the location of the element of `a` at index `b`. The element can be assigned to when the index expression is a mutable place expression (see [expr.mut.valid-places]).
r[expr.array.index.trait]
Otherwise, an index expression `a[b]` is equivalent to `*std::ops::Index::index(&a, b)`, or `*std::ops::IndexMut::index_mut(&mut a, b)` in a [mutable place expression context] when the type of `a` also implements `IndexMut` for the index type of that `Index` implementation, except that when the index expression undergoes [temporary lifetime extension], the indexed expression `a` also has its [temporary scope] extended.
```rust
// The temporary holding the result of `vec![()]` is extended to
// live to the end of the block, so `x` may be used in subsequent
// statements.
let x = &vec![()][0];
# x;
```
```rust,compile_fail,E0716
// The temporary holding the result of `vec![()]` is dropped at the
// end of the statement, so it's an error to use `y` after.
let y = &*std::ops::Index::index(&vec![()], 0); // ERROR
# y;
```
r[expr.array.index.zero-index]
Indices are zero-based for arrays and slices.
r[expr.array.index.const]
Array access is a [constant expression], so bounds can be checked at compile-time with a constant index value. Otherwise a check will be performed at run-time that will put the thread in a [_panicked state_][panic] if it fails.
```rust,should_panic
// lint is deny by default.
#![warn(unconditional_panic)]
([1, 2, 3, 4])[2]; // Evaluates to 3
let b = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
b[1][2]; // multidimensional array indexing
let x = (["a", "b"])[10]; // warning: index out of bounds
let n = 10;
let y = (["a", "b"])[n]; // panics
let arr = ["a", "b"];
arr[10]; // warning: index out of bounds
```
r[expr.array.index.trait-impl]
The array index expression can be implemented for types other than arrays and slices by implementing the [Index] and [IndexMut] traits.
[`Copy`]: ../special-types-and-traits.md#copy
[`Index`]: std::ops::Index
[`IndexMut`]: std::ops::IndexMut
[IndexMut]: std::ops::IndexMut
[Index]: std::ops::Index
[array]: ../types/array.md
[const generic argument]: items.generics.const.argument
[const block expression]: expr.block.const
[constant expression]: ../const_eval.md#constant-expressions
[constant item]: ../items/constant-items.md
[inferred const]: items.generics.const.inferred
[literal]: ../tokens.md#literals
[mutable place expression context]: expr.mut.intro
[panic]: ../panic.md
[path]: path-expr.md
[place expressions]: expr.place-value
[slice]: ../types/slice.md
[temporary lifetime extension]: destructors.scope.lifetime-extension
[temporary scope]: destructors.scope.temporary