Exploring the Core Features of Rust Standard Library

Rust Stack and Heap In Rust

Stack and Heap are parts of memory obtainable to our Rust Programming code to use at runtime.

Rust Program is a memory-safe programming language. For ensure that Rust is memory-safe, it inaugurate conception like ownership, references and borrowing.

To understand these conception, you must first understand how to share out and deallocate memory into the Stack and Heap.

The Stack In Rust

The Stack make be concern of as a stack of books. When you add one more books, you add them and on the top of the pile. When you need a book, then we take one from the top.

The stack implant values in order. Now It gets them and removes the values in the opposite order.

  • To Adding data is called pushing onto the stack
  • To Removing data is called popping off the stack

This phenomenon is called of Last In, First Out (LIFO) in programming.

Data stored on the stack must have a stable size during compile time. Rust Program, by default, allocates memory on the stack for primordial types.

Now Let’s notice how memory is allocated and deallocated on the stack with an example in rust programming.

fn foo() {
    let y = 999;
    let z = 333;
}

fn main() {
    let x = 111;
    
    foo();
}

In the upon example, you can first call the function main(). The main() function pass through one variable binding x.

When main() conduct, you apportion a single 32-bit integer (x) to stack frame.

Screenshot-2024-01-15-205957

In the above table, the “Address” column mention to the memory address of the RAM.

It starts from** 0** and passing to how much RAM (number of bytes) our computer has. The “Name” column mentions to the variable, and the “Value” column mentions to the variable’s value.

Now foo() is named a new stack frame is located. The foo() function has two variable nabbing, y and z.

Screenshot-2024-01-15-210519

The numbers 0, 1, and 2 don’t use address values the system will use in reality. The reality, the addresses are differentiated by some number of bytes based on the value.

Then foo() is performed and its stack frame is deallocated.

Screenshot-2024-01-15-210833

At last, main() is performed, and everything is going away.

Rust Program automatically does allocation and deallocation of memory the in and out of the stack.

The Heap In Rust

As conversed to the stack, most of time, you will need to pass variables (memory) to several functions and keep it them alive for longer than a single function’s performance. that is when you can use the heap.

You can allocate memory of the heap using the Box<T> type. For example-

fn main() {
    let x = Box::new(100);
    let y = 222;
    
    println!("x = {}, y = {}", x, y);
}

Output :

x = 100, y = 222

Now Let’s notice the memory when main() is called in the upon example.

Screenshot-2024-01-15-211450

Before like, you allocate two variables, x and y, on the stack.

But, the value of x is allocated on the heap when Box::new() is designated. this, the actual value of x is a pointer to the heap.

See The memory now looks like as this:

Screenshot-2024-01-15-211839

Below See, the variable x maintain a pointer to the address → 5678, an unrestricted address used for accomplishment. Heap can be allocated and rescued in any order. this, it can end up with several addresses and make holes between addresses.

Now when x going away, it first frees the memory of allocated on the heap.

Screenshot-2024-01-15-212406

At one time the main() is performed, you free the stack frame and everything going away, liberate all the memory.

Rust Vector In Rust programming

Vector is a dynamic (resizable) data structure that can be store a list of elements of the identical type. Entity a resizable data structure, vectors can get and be congruent at runtime.

Create a Vector in Rust Programming

In Rust programming, you can make a vector using the vec! macro. Now see for example- x

let v = vec![1, 2, 3];

Below , you are making a vector by using the vec! macro with some primary values.

  • let v - the name of variable
  • vec![1, 2, 3] - initialize a vector with the integer values 1, 2, 3

By glancing at the type of values provided to the macro, Rust Programming will automatically set of the vector type. For the example, the vector type of the above vector is Vec<i32>.

You can also prescribe the vector type ourselves using the vec! macro.

let v: Vec<u8> = vec![1, 2, 3];

Below, you are making a vector with type u8, who has elements 1, 2 and 3.

Example: Creating a Vector in Rust Programming

fn main() {    
    // vector creation with vec! macro
    let v = vec![1, 2, 3];
    
    println!("v2= {:?}", v);
}

Output :

v = [1, 2, 3]

Elements Accessing of a Vector in Rust Programming

Every element in a vector is connected with a identical sequence of numbers. that number is known as vector index.

You can access elements of a vector by using the vector index. Now suppose we have a vector of colors.

let colors = vec!["blue", "red", "green"];

Below, what is the indexes for this vector to look like-

Screenshot-2024-01-16-225318

You can access several vector elements by using their corresponding vector indexes. For example-

  • colors[0] - access of the element at index 0 (first element)
  • colors[1] - access of the element at index 1 (second element)
  • colors[2] - access of the element at index 2 (third element)

Example: Accessing Elements of a Vector using Vector Index In Rust Program

fn main() {
    let colors = vec!["blue", "red", "green"];
    
    // method 1: access vector elements using vector index
    println!("first color = {}", colors[0]);
    println!("second color = {}", colors[1]);
    println!("third color = {}", colors[2]);
}

**Output: **

first color = blue
second color = red
third color = green

Accessing Elements of a Vector using the get() method in Rust Programming

You can also access the element of vector with the get() method and the index of the element.

Guess we have a vector of colors:

let colors = vec!["blue", "red", "green"];

You can access the elements of the vector manage get(). The get() method does not presently return the vector element but show an enum with type Option<T>. The error result is either a Some(T) or None.

  • colors.get(0) - returns of Some value at** index 0**
  • colors.get(1) - returns of Some value at index 1
  • colors.get(2) - returns of Some value at index 2

Example: Accessing Elements of a Vector using get() In Rust Programming

fn main() {
    let colors = vec!["blue", "red", "green"];
    
    // method 2: access vector elements using get() method and vector index
    println!("first color = {:?}", colors.get(0));
    println!("second color = {:?}", colors.get(1));
    println!("third color = {:?}", colors.get(2));
}

Output :

first color = Some("blue")
second color = Some("red")
third color = Some("green")

As you can see, output returns a value Some("blue"), Some("red") and Some("green") of the Option<T> type of value.

Adding Values to a Vector in Rust Program

You can add values to a Vector by making a mutable vector in Rust program. You can use the mut keyword at first attributing a vector to a variable to make it mutable. For example-

// mutable vector
let mut v = vec![2, 4, 6, 8, 10];

You can add values to this vector by using the push() method.

Now look at an example below-

fn main() {
    let mut even_numbers = vec![2, 4, 6, 8, 10];
    
    println!("original vector = {:?}", v);
    
    // push values at the end of the vector
    even_numbers.push(12);
    even_numbers.push(14);
    
    println!("changed vector = {:?}", v);
}

Output :

original vector = [2, 4, 6, 8, 10]
changed vector = [2, 4, 6, 8, 10, 12, 14]

Here, You can push values to the vector with the push() method. It’s only possible cause the variable holding the vector even_numbers is mutable.

even_numbers.push(12);
even_numbers.push(14);

Result as the final vector includes **12 **and 14 with the default elements.

Values Removing from a Vector in Rust program

You can remove values from a vector by creating it mutable and with the remove() method. For example-

fn main() {
    let mut even_numbers = vec![2, 4, 6, 8, 10];
    
    println!("original vector = {:?}", even_numbers);
    
    // remove value from the vector in its second index
    even_numbers.remove(2);
    
    println!("changed vector = {:?}", even_numbers);
}

Output :

original vector = [2, 4, 6, 8, 10]
changed vector = [2, 4, 8, 10]

See here, you can remove the value in the second index with the even_numbers.remove(2) method. this is the final result does not comprise the value 6 in the vector.

Looping Through a Vector in Rust Program

You can use the for..in loop to repeat through a vector. For example-

fn main() {
    let colors = vec!["blue", "red", "green"];
    
    // loop through a vector to print its index and value
    for index in 0..3 {
        println!("Index: {} -- Value: {}", index, colors[index]);
    }
}

Output :

Index: 0 -- Value: blue
Index: 1 -- Value: red
Index: 2 -- Value: green

In the Upon example, you have used the for…in loop with the range 0..3.

for index in 0...3 {
    ...
}

Below, the loop runs times 3 (0 to 2). In every iteration of the loop, the value of index will be done 0, 1, and 2. You have used this index to access elements of the vector.

Creating a Vector using Vec::new() Method In Rust Program

Alternatively, you can make an empty vector by using the Vec::new() method. For example-

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

we are making an empty vector to hold values of type i32.

  • let v - the name of variable
  • Vec<i32> - type of vector, where i32 is data type of all I in the vector
  • Vec::new() - start an empty vector with of the new() method

Example: Creating a Vector using Vec::new() In Rust Program

fn main() {
    // vector creation with Vec::new() method
    let mut v: Vec<i32> = Vec::new();

    // push values to a mutable vector
    v.push(10);
    v.push(20);

    println!("v = {:?}", v);
}

Output :

v = [10, 20]

Rust String In Rust Program

A string in Rust program is a series of Unicode characters encoded in UTF-8. For example- "Rust Programming" is a string in which every character is a valid Unicode characters. i.e. "R", "u", "s", "t", " ", and so on.

A String Making In Rust

You can make a string with a default value using the String::from() method. For example-

// make a string with a default value
let word = String::from("Hello, World!");

You make a new string and assign it to word variable. You also bargain a default value of "Hello, World!"

Example: Making a String in Rust program

fn main() {
    // string creation using String::from() method
    let word = String::from("Hello, World!");

    println!("word = {}", word);
}

Output :

word = Hello, World!

Mutable String in Rust Program

You can make a mutable string in Rust by using the mut keyword before assigning a string to a variable. For example-

// mutable string
let mut word = String::from("cat");

Now see an Example below-

fn main() {
    let mut word = String::from("cat");
    
    println!("original string = {}", word);
    
    // push a new string at the end of the initial string 
    word.push_str(" dog");
    
    println!("changed string = {}", word);
}

Output :

original string = cat
changed string = cat dog

Here, you make a mutable variable word that holds the string "cat". Then you push a new string to the end of the original string using word.push_str(" dog");.

Slicing String in Rust Program

You can slice a string in Rust Program to mention a part of the string. String slicing accommodate you to reference a part (portion) of a string. For example-

fn main() {
    let word = String::from("Hello, World!");

    // slicing a string
    let slice = &word[0..5];

    println!("string = {}", word);
    println!("slice = {}", slice);
}

Output :

string = Hello, World!
slice = Hello

Below, &word[0..5] is a modulator for slicing the string stored in variable word from start index 0 (inclusive) to end index 5 (exclusive).

Iterating over Strings In Rust

You can exercise the chars() method of the string type to repeat over a string. For example-

fn main() {
    let str = String::from("Hello");
    
    // Loop through each character in a string using chars() method
    for char in str.chars() {
        println!("{}", char);
    }
}

Output :

H
e
l
l
o

Above ,you repeat through all the characters using the chars() method and print every of them.

Creating an Empty String with String::new() In Rust

You can create an empty string, by using the String::new() method. For example-

// create an empty string
let mut word = String::new();

You can after append a string to the word variable using the push_str() method.

word.push_str("Hello, World!");

Example: Creating an Empty String with String::new() In Rust

fn main() {
    // create an empty string
    let mut word = String::new();
    
    println!("original string = {}", word);
    
    // append a string to the word variable
    word.push_str("Hello, World!");

    println!("changed string = {}", word);
}

Output :

original string = 
changed string = Hello, World!

You create an empty string with String::new() and connect a string "Hello, World!"using the push_str() method to the original string.

Rust HashMap In Rust

The Rust HashMap data structure accommodate us to store data in key-value pairs. Below are some of the features of hashmap-

  • Each value is associated with a corresponding key.
  • Keys are unique, whereas values can duplicate.
  • Values can be accessed using their corresponding keys.

Making a HashMap In Rust

HashMap is part of the Rust program grade collections library, so you must cover the HashMap module in our program to use it

use std::collections::HashMap;

You can import the HashMap module exercise the use proposition. It should be at the top of the programming

Now, you can make a hashmap using the new() method in the HashMap module. For example-

let mut info: HashMap<i32, String> = HashMap::new();

Below-

  • let mut info - declare a mutable variable info
  • HashMap<i32, String> - type of the HashMap where the key is Integer and the value is a String
  • HashMap::new() - makes a new HashMap

Example: Making a HashMap In Rust

// import HashMap from Rust standard collections library
use std::collections::HashMap;

fn main() {
    // create a new HashMap
    let mut info: HashMap<i32, String> = HashMap::new();
    
    println!("HashMap = {:?}", info);
}

Output :

HashMap = {}

Operations Of HashMap In Rust

The HashMap module take steps various methods to redact basic operations in a hashmap.

  • Add Elements
  • Access Values
  • Remove Elements
  • Change Elements

1. Add Elements to a HashMap in Rust program

You can conduct the insert() to add an component (key-value pairs) to a hashmap. For example-

let mut fruits: HashMap<i32, String> = HashMap::new();

// insert elements to hashmap
fruits.insert(1, String::from("Apple"));
fruits.insert(2, String::from("Banana"));

Below, you implant two key-value pairs in the HashMap confident to the variable fruits. The String::from() method are creates a value of String type.

Example: Add Elements to a HashMap In Rust

use std::collections::HashMap;

fn main() {
    let mut fruits: HashMap<i32, String> = HashMap::new();
    
    // add key-value in a hashmap
    fruits.insert(1, String::from("Apple"));
    fruits.insert(2, String::from("Banana"));
    
    println!("fruits = {:?}", fruits);
}

Output :

fruits = {1: "Apple", 2: "Banana"}

2. Access Values in a HashMap in Rust Program

You can conduct the get() to access a value from the conferred hashmap. For example-

let mut fruits: HashMap<i32, String> = HashMap::new();

fruits.insert(1, String::from("Apple"));
fruits.insert(2, String::from("Banana"));

let first_fruit = fruits.get(&1);

Example: Access Values in a HashMap In Rust

use std::collections::HashMap;

fn main() {
    let mut fruits: HashMap<i32, String> = HashMap::new();
    
    // insert elements in a hashmap
    fruits.insert(1, String::from("Apple"));
    fruits.insert(2, String::from("Banana"));
    
    // access values in a hashmap
    let first_fruit = fruits.get(&1);
    let second_fruit = fruits.get(&2);
    let third_fruit = fruits.get(&3);
    
    println!("first fruit = {:?}", first_fruit);
    println!("second fruit = {:?}", second_fruit);
    println!("third fruit = {:?}", third_fruit);
}

Output :

first fruit = Some("Apple")
second fruit = Some("Banana")
third fruit = None

Follow that you can use the ampersand(&) and the key (&1, &2) as an contention to the get() method.

let first_fruit = fruits.get(&1);
let second_fruit = fruits.get(&2); 

3. Elements Remove from a HashMap in Rust Program

You can remove elements from a hashmap by shifting a key to the remove() method. For example-

let mut fruits: HashMap<i32, String> = HashMap::new();

fruits.insert(1, String::from("Apple"));
fruits.insert(2, String::from("Banana"));

fruits.remove(&1);

Above, you gather in a value from the hashmap using the key and the remove() method.

Example: Elements Remove in a HashMap In Rust

use std::collections::HashMap;

fn main() {
    let mut fruits: HashMap<i32, String> = HashMap::new();
    
    // insert values in a hashmap
    fruits.insert(1, String::from("Apple"));
    fruits.insert(2, String::from("Banana"));
    
    println!("fruits before remove operation = {:?}", fruits);

    // remove value in a hashmap
    fruits.remove(&1);
    
    println!("fruits after remove operation = {:?}", fruits);
}

Output :

fruits before remove operation = {1: "Apple", 2: "Banana"}
fruits after remove operation = {2: "Banana"}

Above, you gather in an element in the hashmap with key &1 using the remove() method.

4. Elements Change of a HashMap in Rust Program

You can change/update elements of a hashmap by making the insert() method. For example-

let mut fruits: HashMap<i32, String> = HashMap::new();

// insert values in the hashmap
fruits.insert(1, String::from("Apple"));
fruits.insert(2, String::from("Banana"));

// update the value of the element with key 1
fruits.insert(1, String::from("Mango"));

Above, the final insert evolution updates the primary value of the element with the key of 1.

Example: Elements Change of a HashMap In Rust

use std::collections::HashMap;

fn main() {
    let mut fruits: HashMap<i32, String> = HashMap::new();
    
    // insert values in a hashmap
    fruits.insert(1, String::from("Apple"));
    fruits.insert(2, String::from("Banana"));
    
    println!("Before update = {:?}", fruits);
    
    // change value of hashmap with key of 1
    fruits.insert(1, String::from("Mango"));
    
    println!("After update = {:?}", fruits);
}

Output :

Before update = {1: "Apple", 2: "Banana"}
After update = {1: "Mango", 2: "Banana"}

Several Methods of Rust HashMap

Without the basic methods, there are some more commonly used HashMap methods.

Screenshot-2024-01-17-131707

Example: Rust HashMap Methods In Rust Program

use std::collections::HashMap;

fn main() {
    let mut fruits: HashMap<i32, String> = HashMap::new();
    
    fruits.insert(1, String::from("Apple"));
    fruits.insert(2, String::from("Banana"));
    
    // loop and print values of hashmap using values() method
    for fruit in fruits.values() {
        println!("{}", fruit)
    }
    
    // print the length of hashmap using len() method
    println!("Length of fruits = {}", fruits.len());
}

OutPut :

Apple
Banana
Length of fruits = 2

Above, You can use the values() method of the HashMap to loop per its values and len() method of the hashmap to discovery its length.

Previous
Deep Dive into Rust Functions, Variable Scope, and Closures
Next
Rust Error Troubleshooting Comprehensive Guide to Memory Management