Arrays
Arrays in Rust have a fixed size and element type. Additionally, each element must be given a value at initialization. The values may be enumerated in a list literal, as in this declaration:
let xs = [1, 2, 4, 8, 16, 32, 64, 128, 256];
The inferred type of xs
is [u32; 9]
, which means an array of 9 u32
values. We could have written the type explicitly:
let xs: [u32; 9] = [1, 2, 4, 8, 16, 32, 64, 128, 256];
The size is part of the array's type. An array with a different size has a different type. If we add another element to the source code, we must also increase the size in the type from 9 to 10. Otherwise the code won't compile.
Our other option is to initialize all elements of the array with a default value using a repeat expression of the form [value; count]
. This declaration creates an array of 9 100s:
let xs = [100; 9];
We access elements of the array with the subscript operator:
println!("{}", xs[0]);
Out-of-bounds indices cause the program to crash, which is better than accessing unsafe memory. If there's a chance that we may have an out-of-bounds index, we should either check the bounds manually or use the get
method, which returns an Option
.
Though an array must be given initial values, we may overwrite these values if the array is mutable. This code creates an array of zeroes but then overwrites them with powers-of-two:
let mut xs = [0; 9];
for i in 0..xs.len() {
xs[i] = 1 << i;
}
In the languages you've learned previously, you have passed arrays around to other functions with little concern for performance. Arrays are generally passed as pointers or references, which makes them as cheap to pass as primitive types. However, this is not the case in Rust. This program passes an independent copy of the array to printArray
:
fn main() {
let xs = [0; 1000];
printArray(xs);
}
fn printArray(items: [u32; 1000]) {
println("{:?}", items);
}
Additionally, the printArray
function is not very flexible. It only accepts arrays of size 1000. Both the expensive copy and the size inflexibility are fixed by passing an array slice instead of the full array. A slice is passed when we apply the &
operator to the array:
fn main() {
let xs = [0; 1000];
printArray(&xs); // pass as reference
}
fn printArray(items: &[u32]) { // no size is declared
println("{:?}", items);
}
An array slice is to an array as &str
is to String
. As with &str
, an array slice is a reference to a fixed-size window of contiguous elements. The array behind the slice supports non-destructive operations like subscripting and searching and operations that generate new structures, like join.