Focus mode

Rust Programming

Common collections in Rust

In Rust, collections are powerful and versatile tools that enable you to store multiple data elements in a single structure. They are designed to provide an efficient way to manage and manipulate groups of related data while taking advantage of Rust's memory safety and performance features.

By the end of this section, you'll have a solid understanding of the three most used Rust collections: Vectors, Strings, and Hash Maps. You'll learn how to create, manipulate, and iterate through these collections, as well as when to use each one based on your specific needs.

So, let's dive into the world of Rust collections and discover how they can help you write more efficient and elegant code!

Vectors

Vectors are resizable arrays that store elements of the same data type. In this section, we will learn how to create, update, access, and iterate through vectors in Rust.

Creating a Vector

To create a vector, you can use the vec! macro or the Vec::new() function. Here's an example:

// Using the vec! macro
let mut numbers = vec![1, 2, 3, 4];

// Using the Vec::new() function
let mut names: Vec<String> = Vec::new();


The numbers vector is created using the vec! macro, which initializes it with the given values. The names vector is created using the Vec::new() function and is explicitly typed as a vector of String values.

Updating and Accessing Vector Elements

Adding elements to a vector:

let mut names: Vec<String> = Vec::new();
names.push(String::from("Alice"));
names.push(String::from("Bob"));


In this example, we use the push method to add elements to the names vector.

Accessing elements in a vector:

let names = vec![String::from("Alice"), String::from("Bob")];
let first_name = &names[0]; // Accessing the first element using indexing
println!("The first name is: {}", first_name);


Here, we access the first element of the names vector using indexing. Note that the index is zero-based.

Iterating Through a Vector

To iterate through the elements of a vector, you can use a for loop:

let numbers = vec![1, 2, 3, 4];
for number in &numbers {
    println!("Number: {}", number);
}


In this example, we use a for loop to iterate through the elements of the numbers vector and print each element.

Slicing a Vector

You can create a slice of a vector to access a range of elements:

let numbers = vec![1, 2, 3, 4, 5];
let slice = &numbers[1..4];


In this example, we create a slice of the numbers vector that contains elements from index 1 (inclusive) to index 4 (exclusive). The resulting slice contains [2, 3, 4].

In the next sections, we will explore other common collections in Rust, such as strings and hash maps, and learn how to work with them.

Strings

A Brief Reminder on Strings

Strings are a collection of characters, and in Rust, they are implemented as a wrapper over a Vec<u8> to store UTF-8 encoded text. There are two main types of strings: String, which is a growable, mutable, and heap-allocated data structure, and &str, which is an immutable, borrowed reference to a string slice.

Appending to a String

You can append to a String using the push_str method for adding a string slice or the push method for adding a single character:

let mut hello = String::from("Hello, ");
hello.push_str("world!");
hello.push('!');
println!("{}", hello); // "Hello, world!!"

String Slicing and Indexing

Since strings are encoded in UTF-8, indexing them by bytes may not always correspond to a valid Unicode scalar value. Instead, you can use slicing to access parts of a string:

let example = String::from("hello");
let slice = &example[0..2];
println!("{}", slice); // "he"

UTF-8 Encoding and Handling Unicode Scalar Values

Strings in Rust are stored as a sequence of bytes representing UTF-8 encoded text. This means that some characters, such as those from non-Latin scripts or special symbols, may occupy more than one byte.

You can use the chars method to iterate over Unicode scalar values:

let text = "こんにちは";
for c in text.chars() {
    println!("{}", c);
}

Iterating Through a String

You can use the chars method to iterate through the characters of a string or the bytes method to iterate through the individual bytes:

let example = String::from("hello");

// Iterate over characters
for c in example.chars() {
    println!("{}", c);
}

// Iterate over bytes
for b in example.bytes() {
    println!("{}", b);
}

Hash Maps

In this section, we will explore hash maps in Rust, which allow you to store data in key-value pairs. Hash maps are particularly useful when you want to look up values based on a specific key efficiently.

Introduction to Hash Maps

A hash map is a collection that associates a key with a value. It uses a hashing function to compute an index into an array of buckets or slots, from which the desired value can be found. This makes hash map operations fast, as it can directly access the value using the key.

Creating a Hash Map

To create a hash map, you can use the HashMap type from the std::collections module. Let's see an example of how to create a hash map to store the scores of different players:

use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Alice"), 10);
    scores.insert(String::from("Bob"), 20);
}


In this example, we first import the HashMap type from the std::collections module. Then, we create a mutable variable scores and initialize it with an empty hash map using HashMap::new(). We insert key-value pairs into the hash map using the insert method, where the keys are player names (String) and the values are their scores (i32).

Accessing and Updating Hash Map Elements

To access the value associated with a key, you can use the get method. This method returns an Option<&V>, where V is the value type:

fn main() {
    // ... (the previous code)

    let alice_score = scores.get(&String::from("Alice"));
    println!("Alice's score: {:?}", alice_score);
}


Here, we call the get method with a reference to the key and print the value. Since the get method returns an Option<&V>, we use the {:?} format specifier to print the Option type.

To update a value in the hash map, you can use the insert method again:

fn main() {
    // ... (the previous code)

    scores.insert(String::from("Alice"), 30);
    println!("Updated scores: {:?}", scores);
}


In this example, we update Alice's score to 30. If the key already exists, the insert method will replace the old value with the new one.

Removing Elements from a Hash Map

You can remove a key-value pair from a hash map using the remove method:

fn main() {
    // ... (the previous code)

    scores.remove(&String::from("Alice"));
    println!("Scores after removing Alice: {:?}", scores);
}


Here, we remove the key-value pair associated with the key "Alice" and print the updated hash map.

Iterating Through a Hash Map

To iterate through a hash map, you can use a for loop:

fn main() {
    // ... (the previous code)

    for (key, value) in &scores {
        println!("{}: {}", key, value);
    }
}


This code iterates through the key-value pairs in the hash map and prints them.

Comparison of Collection Types

In this part, we will summarize the differences between vectors, strings, and hash maps, and discuss when to use each collection type in Rust.


Vectors

  • Vectors store elements of the same type in a contiguous memory space, which makes them ideal for handling ordered lists of elements.
  • Vectors automatically resize themselves when needed, making them a dynamic alternative to arrays.
  • When to use: You should choose vectors when you need a dynamic, ordered collection of elements where all elements have the same type.

Strings

  • Strings are used for storing and manipulating text data. They handle UTF-8 encoded text, which allows the representation of a wide range of characters.
  • The String type is mutable and can grow or shrink as needed.
  • When to use: You should use strings when you need to store or manipulate text data, while ensuring proper handling of Unicode characters.

Hash Maps

  • Hash maps store key-value pairs, allowing you to associate a value with a unique key.
  • They provide quick lookup, insertion, and deletion of elements based on the key.
  • When to use: Choose hash maps when you need to store data in a collection with unique keys and fast retrieval times, or when you want to quickly find a value based on a specific key.

In summary, each collection type has its own strengths and use cases. Vectors are suitable for ordered lists of elements, strings are essential for text data manipulation, and hash maps excel at quickly associating values with unique keys. By understanding the distinctions between these collection types, you can effectively choose the most suitable one for your specific programming needs.

Test

Comments

You need to enroll in the course to be able to comment!