Arrays, vectors, and slices

Suppose we have a bunch of alien creatures to populate a game level, then we probably want to store their names in a handy list. Rust's array is just what we need:

// from Chapter 4/code/arrays.rs 
let aliens = ["Cherfer", "Fynock", "Shirack", "Zuxu"]; 
println!("{:?}", aliens); 

To make an array, separate the different items by commas and surround the whole with [ ] (rectangular brackets). All items must be of the same type. Such an array is of fixed size (it must be known at compile time) and cannot be changed; it is stored in one contiguous piece of memory in stack memory.

If the items have to be modifiable, declare your array with let mut; however even then the number of items cannot change:

let mut aliens = ["Cherfer", "Fynock", "Shirack", "Zuxu"]; 

The array aliens could be type annotated as [&str; 4], where the first parameter is the type of the items, and the second is their number.

let aliens: [&str; 4] = ["Cherfer", "Fynock", "Shirack", "Zuxu"]; 

If we want to initialize an array with three Zuxus, that's easy too:

let zuxus = ["Zuxu"; 3]; 

How would you make an empty array? Like this:

let mut empty: [i32; 0] = []; 
println!("{:?}", empty); // [] 

We can access individual items with their index, starting from 0:

println!("The first item is: {}", aliens[0]); // Cherfer 
println!("The third item is: {}", aliens[2]); // Shirack 

The number of items in the array is given by aliens.len(), so how would you get the last item?

Using the following statement:

aliens[aliens.len() - 1] 

Alternatively, this can be found with the following statement:

aliens.iter().last().unwrap(); 

What do you think will happen when we try to change an item, like this?

aliens[2] = "Facehugger"; 

Hopefully you didn't think that Rust would allow this, did you? Unless you told it explicitly that aliens can change with the following statement:

let mut aliens = [...]; 

In many cases the compiler checks whether the array index stays within the array bounds.

The index is also checked at runtime to be within the array bounds 0 and aliens.len(); if it is not, the program crashes with a runtime error or panic:

println!("This item does not exist: {}", aliens[10]); 

This gives the following output:

thread '<main>' panicked at 'index out of bounds: the len is 4 but the index is 10'  

Pointers to arrays use automatic dereferencing so that you do not need to use * explicitly, as demonstrated in this code snippet:

let pa = &aliens; 
println!("Third item via pointer: {}", pa[2]); 

This prints the following output:

Third item via pointer: Shirack

If we want to go through the items successively one by one, and print them out or do something useful with them, we can do it like this:

for ix in 0..aliens.len() { 
    println!("Alien no {} is {}", ix, aliens[ix]); 
} 

This works and it gives us for each item its index, which might be useful. But we use the index to fetch each consecutive item, and each time Rust has to check whether we are still within the bounds of the array in memory. That's why it is not very efficient, and in the section Iterators in Chapter 6, Using Traits and OOP in Rust, we will see a much more efficient way by iterating over the items:

for a in aliens.iter() {    
    println!("The next alien is {}", a); 
} 

The for loop can be written even shorter as:

for a in &aliens  { ... }