Rust Intermediate

Intermediate Rust

Rust Intermediate

Advanced-Data Structures in Rust

Advanced-Data Structures in Rust

Aside from data types and primary data structures, Rust supports more advanced data structures like HashMaps and Sets. Before we look into them, let’s refresh our memory on the Vector data structure.

Vectors

We defined Vectors as dynamic arrays that can grow or shrink in size. That is, elements stored in a Vector (denoted with Vec<T> in Rust, where T stands for the data type of the elements) are stored next to each other in memory. Let’s see how Vectors are created in Rust. Create a new project:

cargo new learn_rust

Inside the main.rs file, write this function by hand:

pub fn create_vector() {
    // Create a new mutable vector of type i32.
    let mut new_vector: Vec<i32> = Vec::new();
    // Print out the content of the vector.
    println!("Vector content: {:?}", new_vector);
    // Push a value into the vector.
    new_vector.push(1);
    // Print out the new content of the vector.
    println!("Vector content: {:?}", new_vector);
}

You should see the output:

Vector content: []
Vector content: [1]

This is how to create and update a Vector. Vectors also have these important functions that save you time:

  • .remove() to remove an element from the Vector.

  • .get() to access an element using its index.

  • for .. in .. loop for iteration.

Note: The Vector accepts any type T, meaning any of these can be done in Rust:

pub fn pass_all_data_types_to_vectors() {
    // integer values.
    let numbers: Vec<i32> = vec![1,2,3,4,5];
    // floating point values.
    let temperatures: Vec<f64> = vec![36.6, 27.0, 15.3];
    // strings.
    let names: Vec<String> = vec!["Bob".to_string(), "Alice".to_string()];
    // booleans.
    let flags: Vec<bool> = vec![true, false, true, true];
    // custom structs.
    struct Person {
        name: String,
        age: u32,
    }
    let people: Vec<Person> = vec![
        Person { name: "Bob".to_string(), age: 27 },
        Person { name: "Alice".to_string(), age: 37 },
    ];
    // enums:
    enum FilterOptions {
        Free,
        Paid,
        Bonus,
    }
    let filters: Vec<FilterOptions> = vec![FilterOptions::Free, FilterOptions::Paid, FilterOptions::Bonus];
    // mixed types using trait objects.
    let mixed: Vec<Box<dyn std::fmt::Debug>> = vec![
        Box::new(42),
        Box::new("Alice".to_string()),
    ];
}

Now that we understand Vectors, let’s explore HashMaps.

HashMaps

HashMaps in Rust are similar to Maps or HashMaps in another programming language. They are used to map keys of any type to values of any type. Let’s see how to create and populate a HashMap:

// Import collections package from STD.
use std::collections::HashMap;

pub fn create_hashmap() {
    // Create a new hashmap.
    let mut data = HashMap::new();
    // Insert data into this hashmap.
    data.insert(String::from("One"), 1);
    data.insert(String::from("Two"), 2);
    // Check the content of the hashmap.
    println!("Content of data: {:?}", data);
}

Next, let’s see how to access a value in the HashMap or return a message if the value is not found:

    // Accessing value in the HashMap.
    if let Some(data) = data.get("One") {
        println!("The first data here is: {}", data);
    } else {
        // Handling Nonexistent keys.
        println!("That data is not found.");
    }

Finally, let’s see how to iterate over the values in the HashMap and how to remove values from it:

    // Iterating over the HashMap.
    for (key, data) in &data {
        println!("{} matches with {}", key, data);
    }

    // Remove values form the HashMap.
    data.remove("Two");
    println!("Content of data: {:?}", data);

In several software systems, HashMaps are often used in the following scenarios:

  1. In implementing caching mechanisms, quick lookups will reduce resource-intensive operations like database queries or expensive calculations.

  2. In user session management, store session information like user IDs, session tokens, etc., and quickly find an account using a credential such as email.

  3. In data indexing and searching operations popular in search engines of different systems.

  4. Managing resources like database connections, threads, network sockets, etc., is important in resource pools.

  5. Others.

Note: If you want to quickly simulate a database but don’t want to go through the stress of setting up one, you can quickly simulate one in your code using a HashMap, as you have seen. In the next section, you will see an example of this.

Great! Now that we have learned about Collections in Rust let’s move on to more important concepts: Methods and Enumerations.

Exercises

  1. Vectors and HashMaps: Write a program that stores user input in a vector. Implement a function that finds the frequency of each unique element in the vector and displays the results using a HashMap.

  2. Iteration Patterns: Create a custom struct containing information about books (title, author, genre, etc.). Store multiple instances of this struct in a vector. Use iteration patterns to filter and display specific books based on certain criteria.

Whenever you're ready

There are 4 ways we can help you become a great backend engineer:

The MB Platform

Join 1000+ backend engineers learning backend engineering. Build real-world backend projects, learn from expert-vetted courses and roadmaps, track your learnings and set schedules, and solve backend engineering tasks, exercises, and challenges.

The MB Academy

The “MB Academy” is a 6-month intensive Advanced Backend Engineering BootCamp to produce great backend engineers.

Join Backend Weekly

If you like post like this, you will absolutely enjoy our exclusive weekly newsletter, Sharing exclusive backend engineering resources to help you become a great Backend Engineer.

Get Backend Jobs

Find over 2,000+ Tailored International Remote Backend Jobs or Reach 50,000+ backend engineers on the #1 Backend Engineering Job Board