Vectors in Rust

Introduction to Vectors in Rust

Hello! Today, we’re going to delve into one of Rust’s most versatile and powerful data structures — vectors. Just as we explored arrays in our previous lesson, vectors also store a collection of elements of the same type. However, unlike arrays, vectors are dynamic and can grow and shrink as needed.

In this lesson, we'll cover the essentials of creating, modifying, and managing vectors in Rust. We’ll look into different ways of creating vectors, adding and removing elements, and understanding how Rust handles data and ownership within vectors. By the end of this lesson, you'll have a strong grasp of vectors and be ready to use them effectively in your Rust programs.

Let's get started!

Creating Vectors

Vectors can be created in Rust with or without specifying the data type explicitly. If the type is not explicitly mentioned, Rust will infer it based on the values pushed into the vector. To declare a new vector explicitly use Vec followed by the data type within <>. To add new elements to a vector, use push to append the new value to the end of the vector. To implicitly declare a vector, use vec! followed by the elements inside brackets.

Here are a couple of examples to illustrate this:

fn main() {
    // Creating Vector with Data Type
    let mut vector_with_type: Vec<i32> = Vec::new();
    vector_with_type.push(1);
    vector_with_type.push(2);
    vector_with_type.push(3);

    // Creating Vector without Data Type (type inference)
    let mut vector_without_type = vec![4, 5, 6];
    vector_without_type.push(7);
}

In this example:

  • vector_with_type is explicitly typed as a vector of i32 values. Elements are pushed into the vector using the push method.
  • vector_without_type uses type inference, determining the type from the initial values provided.

Accessing Elements of a Vector

You can access elements of a vector using both the get method and direct indexing. The get method returns an Option type that can be used to handle out-of-bounds errors gracefully. The get method returns an Option<&T> where T is the type of the elements in the vector. The Option type can be Some(&element) if the index is valid, or None if the index is out of bounds.

To ensure the valid access of an element, use the pattern matching construct if let Some(&element) = vector.get(index). If index is indeed a valid index, element takes on the value of the element in the vector, and the if block is executed. If index is not a valid index, element takes on the value of None, and the if block does not execute.

fn main() {
    let vector = vec![1, 2, 3];
    if let Some(first_elem) = vector.get(0) {
        println!("First element (using get): {:?}", first_elem); // Prints: First element (using get): 1
    }
    println!("Second element (using index): {}", vector[1]); // Prints: Second element (using index): 2
}
  • If 0 is a valid index of vector (it is), vector.get(0) returns Some(&first_elem) and binds first_elem to the value of the first element of vector.
  • The if block is executed because Some(first_elem) is not None.
  • vector[1] directly accesses the second element but can panic if the index is out-of-bounds.
Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal