2.4 KiB
Arrays
As soon as we start talking about "ticket management" we need to think about a way to store multiple tickets. In turn, this means we need to think about collections. In particular, homogeneous collections: we want to store multiple instances of the same type.
What does Rust have to offer in this regard?
Arrays
A first attempt could be to use an array.
Arrays in Rust are fixed-size collections of elements of the same type.
Here's how you can define an array:
// Array type syntax: [ <type> ; <number of elements> ]
let numbers: [u32; 3] = [1, 2, 3];
This creates an array of 3 integers, initialized with the values 1
, 2
, and 3
.
The type of the array is [u32; 3]
, which reads as "an array of u32
s with a length of 3".
Accessing elements
You can access elements of an array using square brackets:
let first = numbers[0];
let second = numbers[1];
let third = numbers[2];
The index must be of type usize
.
Arrays are zero-indexed, like everything in Rust. You've seen this before with string slices and field indexing in
tuples/tuple-like variants.
Out-of-bounds access
If you try to access an element that's out of bounds, Rust will panic:
let numbers: [u32; 3] = [1, 2, 3];
let fourth = numbers[3]; // This will panic
This is enforced at runtime using bounds checking. It comes with a small performance overhead, but it's how
Rust prevents buffer overflows.
In some scenarios the Rust compiler can optimize away bounds checks, especially if iterators are involved—we'll speak
more about this later on.
If you don't want to panic, you can use the get
method, which returns an Option<&T>
:
let numbers: [u32; 3] = [1, 2, 3];
assert_eq!(numbers.get(0), Some(&1));
// You get a `None` if you try to access an out-of-bounds index
// rather than a panic.
assert_eq!(numbers.get(3), None);
Performance
Since the size of an array is known at compile-time, the compiler can allocate the array on the stack. If you run the following code:
let numbers: [u32; 3] = [1, 2, 3];
You'll get the following memory layout:
+---+---+---+
Stack: | 1 | 2 | 3 |
+---+---+---+
In other words, the size of an array is std::mem::size_of::<T>() * N
, where T
is the type of the elements and N
is
the number of elements.
You can access and replace each element in O(1)
time.