Welcome to the Ultimate Rust Learning Guide

This Notion page is designed to help you dive deep into Rust—a powerful, modern programming language known for its speed, memory safety, and concurrency. This guide will walk you through all the key concepts, from basic syntax to some intermediate Topics such as Generics, Traits and lifetimes and some advance topics such as smart pointers , Declarative Macros, Procedural Macros, Concurrency and many more.

References

The content in this guide draws from various reliable Rust learning resources, including:

This Notion page consolidates and simplifies key concepts from these sources, making them easier to grasp while building a solid foundation in Rust.

Who is this guide for?

Why Rust?

Rust is fast, memory-safe, and allows fearless concurrency. It’s increasingly being adopted in industries ranging from system programming to web development.

Rust vs Other Languages

Aspect Typescript Python C Rust
Typing Static Dynamic Static Static
Memory Management Garbage Collected Garbage Collected Manual (Shooting at the foot) Manual with safety checks
Compilation Transpiles to JavaScript (JIT) Interpreted Ahead-of-time Ahead-of-time
Concurrency Single Threaded Multi-threaded (limited by GIL in CPython, no limit in other implementations like Jython) Manual Thread management Built in concurrency model
Use case Web dev , server side scripting (with NodeJS) Web dev, data analysis , scripting Systems Programming, Embedded Systems, OS Development Systems Programming, Web Assembly , Web servers etc.
Performance Depends on the JS engine Slower (interpreted lang) Fast ( Low Level lang ) Fast (Low level lang with zero cost abstractions)
Error Handling Try/catch exceptions Try/except exceptions Return codes (No built in exception handling ) Result and Option types for error handling.

0. Entry Point

In Rust, every program starts execution from the main function, similar to many other languages like C, C++, and Java. The main function is the entry point of your Rust program, and it's required in every executable Rust project.

fn main(){
	//Write your code here.
}

Breaking it down

fn main() {.....}

1. Hello world

//main.rs
fn main(){
	println!("Hello World"); //prints hello world with a new line on the std output.
}

Breaking it down

println!(”Hello World”);

2. Cargo: The Build System and Package Manager

Cargo is Rust`s Build system and package manager, it plays a crucial role in managing dependencies , compiling code, running tests etc.

Here are some uses

  1. Create a rust project using cargo:

    $ cargo new helloworld helloworld here is a project name.

    1. You will get something like this:

      helloworld/ ├── Cargo.toml └── src └── main.rs

      1. Here we have a main.rs file which contains the main function and a cargo.toml file which contains your projects metadata and dependencies just like a package.json file in javascript if you are from a javascript background.

        [package]
        name = "helloworld"
        version = "0.1.0"
        edition = "202X"
        
        [dependencies]
        //your dependencies 
        
  2. Building your project using Cargo:

    1. $ cargo build this will compile your code (we can add some flags but lets keep it simple for now)
  3. Run Your Project:

    1. Remember last time when we need to run rust code we have to compile it using the rustc compiler and then run it manually , But now cargo will do that for us we just need to run :

      $ cargo run this compile and run the project.

  4. Adding an external Crate (Dependency):

    1. $ cargo add rand → rand is a crate name i want to add to my project.
      1. if you now check your cargo.toml file it will look something like this:

        [package]
        name = "helloworld"
        version = "0.1.0"
        edition = "202X"
        
        [dependencies]
        rand = "0.8.5" //this is the crate with the version number
        
        
  5. We can learn more about cargo like cargo workspaces , but for now this is enough for us to work with rust.

3. Data Types

Every value in rust has a type, which determines what kind of data it can store and how it can be used. And all the types must be known at the compile time. There are a variety of built in datatypes.

1.Scalar Types

These types represent a single value, There are four primary scalar types

  1. Integers:
    1. Signed Integers : i8, i16, i32, i64, i128, isize
    2. Unsigned Integers: u8, u16, u32, u64, u128, usize
  2. Floating points
  3. Booleans
  4. Characters.
let x : u8 = 12;

printnln!("{}",x); //12

<aside> 💡

</aside>

let is used to declare variable x.

2. Compound Types

Compound types can store multiple values into the single type. There are two primary compound types in rust.

  1. Tuples

    1. A group of different types into a single type, All types does not have to be the same.
    let data:(132,f32,char,bool) = (12,12.2,'A',false);
    
    //we can destructure the values 
    let (twelve, twelve_point, letter, is_dead) = data;
    
    println!("twelve: {}, twelve_point: {}, letter:{} is_dead:{} ",twelve, twelve_point, letter, is_dead);
    
    let firstElm = data.0; //12
    let secondElm = data.1; //12.2
    
  2. Arrays

    1. Array is a collection of values of same type store in a contiguous block of memory with a fixed length.

      // [i8; 5] -> i8 is the type of the elements in the array and 5 is the size of the array
      let nums: [i8;5] = [1,2,3,4,5]; //array of 5 8 bit ints
      let firstElm = nums[0]; //1
      let secondElm = nums[1]; //2
      
      //Create an array of size 5 and fill it with zeros;
      let zeros: [i8,5] = [0;5]; //[0,0,0,0,0]
      let length_of_array = zero.len(); //5 -> lenght of the array
      
      //MULTI DIMENSIONAL Arrays
      let matrix: [[i32;3];2] = [
      	[1,2,3],
      	[4,5,6],
      ]
      
      //Iteration over arrays
      
      let numbers = [1,2,3,4,5];
      for num in numbers.iter(){ //for now just ignore .iter() we will cover it later.
      	println!("{}",num);
      }
      

      <aside> 💡

      </aside>

4. Ownership and Borrowing

Ownership is one of Rust’s most distinctive features. It's a system that ensures memory safety without needing a garbage collector. In Rust, each value has a single owner, and once the owner goes out of scope, the value is dropped.

Rules…

Rust has three main rules for ownership:

  1. Each value in Rust has an owner.
  2. There can only be one owner at a time.
  3. When the owner goes out of scope, the value is dropped.

Example

{
    let x = String::from("Hello");  // `x` owns the String.
    // Do something with `x`
} // `x` goes out of scope and the memory is freed.

Once x goes out of scope, Rust automatically frees the memory allocated for the string. You don’t need to manually de-allocate it like in C or C++.

Moving vs Copying

Rust enforces single ownership by moving ownership when a variable is assigned to another.

let str1 = String::from("Hello");
let str2 = str1;  // Ownership of the String moves from `str1` to `str2`.
// `str1` is now invalid.

After the move, s1 is no longer valid, and trying to use it will cause a compile-time error. However, simple types like integers implement the Copy trait, so they are copied rather than moved:

let x = 5;
let y = x;  // `x` is copied to `y`, so both are valid.
println!("x: {}, y: {}", x, y);

<aside> 💡

</aside>

Borrowing References