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!
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:
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
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 String
s, 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:
З
д
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.
Hello, my name is Hoai - a developer who tells stories through writing ✍️ and creating products 🚀. With many years of programming experience, I have contributed to various products that bring value to users at my workplace as well as to myself. My hobbies include reading, writing, and researching... I created this blog with the mission of delivering quality articles to the readers of 2coffee.dev.Follow me through these channels LinkedIn, Facebook, Instagram, Telegram.
Comments (1)