Rust Vector Collection Tutorial
In this Rust tutorial we learn about the vector collection, an array that can be resized by pushing or removing items from its stack.
We learn the macro and new() method to instantiate a vector struct, how to add and remove elements and how to access elements without Rust having a panic.
Lastly, we look at how to find out if a value exists inside a vector.
What is a vector
A vector is a generic collection that can be resized. We can think of it as a resizable array.
Like an array, a vector has a corresponding numerical index and will store its values in contiguous memory blocks on the heap.
The main benefit of a vector is that it can grow and shrink at runtime. Values can be appended to the end of a vector, making it similar to a stack in other languages such as C#.
How to create (instantiate) a new vector
Rust provides us with two methods to create a new vector. We can create a new vector instance by instatiation or via a specialized macro.
The macro is the easiest so let’s start with that.
let vector_name = vec![value_1, value_2, ...];
fn main() {
let num = vec![10, 20, 30, 40, 50];
}
In the example above, we create a new int32 vector with 5 numerical values. The macro is typically used to to create a vector when we know at least one value beforehand.
The second method is by instantiation (creating a new instance of the vector struct).
To instantiate a new vector, we have to give it a type between the angle brackets as well as use the new() static method.
let vector_name: Vec<type> = Vec::new();
fn main() {
let num: Vec<i32> = Vec::new();
}
In the example above, we instantiate a new int32 vector with no values. Instantiation is used to create a vector when we don’t know which values it will hold, only the type.
How to access vector values
Rust provides us with two methods to access elements in a vector. We can access values with either the indexer, or with the get() method.
Let’s take a look at the indexer first.
vector_name[index];
fn main() {
let num = vec![10, 20, 30, 40, 50];
println!("num[0]: {}", num[0]);
println!("num[1]: {}", num[1]);
println!("num[2]: {}", num[2]);
println!("num[3]: {}", num[3]);
println!("num[4]: {}", num[4]);
}
Remember that any array or collection with a numerical index will start at index 0 and not 1.
The problem with the indexer is that when we try to access an element that doesn’t exist, Rust will panic and the program will crash.
The solution is to either write an if statement with the contains() method (covered further down below), or use the get() method which won’t cause Rust to panic.
vector_name.get(index);
fn main() {
let num = vec![10, 20, 30, 40, 50];
println!("num[0]: {:?}", num.get(0));
println!("num[1]: {:?}", num.get(1));
println!("num[2]: {:?}", num.get(2));
println!("num[3]: {:?}", num.get(3));
println!("num[4]: {:?}", num.get(4));
// try to access an element that
// doesn't exist
println!("num[5]: {:?}", num.get(5));
}
In the example above, when we try to access an element that doesn’t exist, Rust doesn’t panic and instead only prints None (Rust’s version of null).
We can also access a vector in a for loop.
fn main() {
let num = vec![10, 20, 30, 40, 50];
for x in num.iter() {
println!("{}", x);
}
}
How to add vector values
To add values to a vector, we push them onto the end of the vector stack with the push() method.
vector_name.push(value);
fn main() {
let mut num: Vec<i32> = Vec::new();
num.push(50);
num.push(40);
num.push(30);
num.push(20);
num.push(10);
for x in num.iter() {
println!("{}", x);
}
}
In the example above, we push items onto the vector’s stack in reverse order (from 50 to 10). This demonstrates how values are added to the end of the stack.
How to remove vector values
To remove values from a vector, we use the remove() method with the index number of the value we want to remove.
When a value is removed, it will push the remaining values after it down by 1.
vector_name.remove(value);
fn main() {
let mut num = vec![10, 20, 30, 40, 50];
// remove [2] (30)
num.remove(2);
println!("num[0]: {}", num[0]);
println!("num[1]: {}", num[1]);
println!("num[2]: {}", num[2]);
println!("num[3]: {}", num[3]);
}
In the example above, we remove the element at index 2 (30). The values are shifted to take the space of removed elements to 40 will now occupy index 2.
How to find a value inside a vector
We can check if a value exists inside a vector by using the contains() method.
vector_name.contains(&value);
fn main() {
let mut num = vec![10, 20, 30, 40, 50];
if num.contains(&30) {
println!("The vector contains the value 30");
} else {
num.push(30);
}
}
In the example above, we check if the vector contains the value 30. If it does, print out a simple message, otherwise add the value.
Summary: Points to remember
- A vector is a resizable collection of items of the same type, similar to an array.
- We create a vector with a macro, or instantiate a new instance with the new() method.
- We access values with the indexer, or with the get() method.
- The get() method won’t panic if we try to access a value that doesn’t exist.
- We add an element to a vector with the push() method.
- We remove a vector element with the remove() method.
- When an element is removed, those above it will be shifted down one (-1 index).
- We can test if a value exists within a vector with the contains() method.