One Month Learning Rust - Collections

One Month Learning Rust - Collections

Daily short news for you
  • These past few days, I've been redesigning the interface for the note-taking app OpenNotas. It's quite strange to think about why I chose DaisyUI back then 😩

    » Read more
  • Previously, there was a mention of openai/codex - a type of agent that runs conveniently in the Terminal from OpenAI, especially since it is open source and they have now added support for other providers instead of just using the chatgpt model as before.

    Recently, Anthropic also introduced Claude Code which is quite similar to Codex, except it is not open source and you are required to use their API. Since I don't have money to experiment, I've only heard that people in the programming community praise it a lot, and it might even be better than Cursor. On the flip side, there's the risk of burning a hole in your wallet at any moment 😨

    » Read more
  • For a long time, I have been thinking about how to increase brand presence, as well as users for the blog. After much contemplation, it seems the only way is to share on social media or hope they seek it out, until...

    Wearing this shirt means no more worries about traffic jams, the more crowded it gets, the more fun it is because hundreds of eyes are watching 🤓

    (It really works, you know 🤭)

    » Read more

Issue

So it has been one month, or more like 5-6 days since I started writing my own self-study series on Rust. As stated from the beginning, it was meant to be a "commitment" to learning and also a way to summarize what I have learned, share it, and hopefully receive feedback to point out any mistakes I have made.

At the end of the month, the progress we have made is not even half of the set goal. Honestly, with limited time, reading has been challenging, and writing even more so, not to mention the time allocated for other tasks. Actually, I don't want to blame the circumstances, as I was aware of this from the beginning. I was prepared for it, but I'm ready to face it and put in effort every day, reaching as far as I can because at least I'm not standing still.

Of course, the series on Rust is not over yet, but I will spread out the articles instead, making room for other topics to avoid monotony for both myself and the readers.

But honestly, the self-study series on Rust could be the biggest success in my one-month timeline, evidenced by many readers, some of whom provide feedback, point out mistakes, and even suggest studying together... These are truly valuable things. Once again, thank you, readers, for taking the time for me. The feeling of someone caring about me, my enthusiasm is like a child who can't sleep because they know that tomorrow their parents will take them to explore the land of dreams.

Without further ado, let's continue exploring what Collections in Rust have to offer!

Collections

The standard library of Rust includes a set of useful data structures called Collections. Most other data types represent a specific value, but Collections can store multiple values. Unlike arrays and tuples, the data that Collections point to is stored on the heap, meaning that the amount of data doesn't need to be known at compile time and can grow or shrink as the program runs. Collections include:

  • A vector that allows you to store a variable number of values next to each other.
  • A string which is a collection of characters.
  • A hash map that allows you to create data structures that store key-value pairs.

Storing a List of Values with Vectors

From the beginning, readers have encountered many examples of the Vector data type created with the vec! macro. Yes, Vectors are a collection type in Rust, or in other words, they are a collection of data.

The syntax to create a Vector is:

let v: Vec<i32> = Vec::new();

It's quite verbose, so let's use the macro instead:

let v = vec![0];

Adding data to Vectors:

v.push(1);
v.push(2);
v.push(3);

Reading an element:

let one = &v[1];

So what happens if you read an element "beyond the range"?

let nine = &v[9];

Well, it's not recommended, so the best approach is to use the get method of the Vector. get returns an Option enum, and remember the knowledge from the previous article to handle the returned value:

let third: Option<&i32> = v.get(2);
match third {
    Some(third) => println!("The third element is {third}"),  
    None => println!("There is no third element."),  
}

String

String and string in Rust may look similar but they work differently. While string is encoded (with the &str data type) and stored statically in the application's binary, String is the opposite - it is stored in the heap and ready to change its value and size.

To explain this, Rust says that this data type is relatively complex to handle, depending on the programming language to implement it in a reasonable way. For them, this is one of the many options available.

Syntax to create a String:

let mut s = String::new();

Or creating a String from a given character string:

let s = String::from("initial contents");

We can also convert data of the &str type to String:

let data = "initial contents";
let s = data.to_string();

Some basic operators on the String type include:

# Append a character string
let mut s = String::from("foo");
s.push_str("bar");

# Append a single character
s.push("b");

# Or concatenate strings using the + operator
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2;

Note that after the "+" operator between two Strings, s1 will be freed and you need to use a reference &s2.

To avoid complexity or ownership issues, we can concatenate strings using the format! macro:

let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = format!("{s1}-{s2}");

Similar to JS, we can iterate through each character in a string like this:

for c in "Зд".chars() {
    println!("{c}");
}

Output:

З
д

Key-Value with Hash Maps

In JavaScript, we have a Map object that allows us to store data in key-value pairs. In Rust, Hash Maps do the same.

Syntax to create a Hash Map:

use std::collections::HashMap;

let mut scores = HashMap::new();

scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);

Reading a value from a key:

let team_name = String::from("Blue");
let score = scores.get(&team_name).copied().unwrap_or(0); // 10

Use the get method to read a value; it returns an Option<&V>, which is a reference to some data type V. In the example above, copied is used to obtain an Option<i32>, which is 10. unwrap_or handles the error in case the key-value pair to be retrieved doesn't exist and returns 0.

We can also iterate through key-value pairs in a Hash Map:

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

Finally, since all data in these Collections is stored on the heap, they have ownership, so be careful when handling them.

Premium
Hello

5 profound lessons

Every product comes with stories. The success of others is an inspiration for many to follow. 5 lessons learned have changed me forever. How about you? Click now!

Every product comes with stories. The success of others is an inspiration for many to follow. 5 lessons learned have changed me forever. How about you? Click now!

View all

Subscribe to receive new article notifications

or
* The summary newsletter is sent every 1-2 weeks, cancel anytime.

Comments (1)

Leave a comment...
Avatar
Ẩn danh1 year ago

seri về Rust có lẽ e sẽ không đọc, nhưng khi nào e học nó thì e sẽ quay lại và đọc những bài viết này

Reply
Avatar
Xuân Hoài Tống1 year ago

Chúc e sớm nắm R trong lòng bàn tay nhé 😄