Introduction

Welcome to the Rust Handbook! This guide is a record of my personal journey as I learn the Rust programming language. Throughout this book, I will document my experiences, challenges, and progress as I dive deeper into Rust, while providing examples, explanations, and lessons learned along the way.

Why Rust?

Rust is a systems programming language focused on safety, performance, and concurrency. It's a great choice for those who want to write fast, memory-safe, and reliable code. Whether you're interested in low-level programming or building scalable applications, Rust has you covered.

  • Memory safety without a garbage collector.
  • Concurrency made easy without the usual pitfalls.
  • Zero-cost abstractions that don’t sacrifice performance.

This book is an ongoing project that serves as a personal documentation of my learning process and a way to reflect on the things I’ve learned.

Who is this book for?

This book is written for anyone who:

  • Is new to Rust and looking for a structured way to learn the language.
  • Has experience with other programming languages and wants to explore Rust’s unique features.
  • Enjoys hands-on learning with practical examples.

Structure of the Book

The book is organized into chapters, each focusing on specific topics that will help you get started and deepen your knowledge of Rust. Here's an overview of the structure:

  1. Introduction to Rust – A brief introduction to the language, its history, and why it’s so popular.
  2. Getting Started with Rust – How to install Rust and set up your development environment.
  3. Basic Syntax and Data Types – Covering variables, types, functions, and control flow.
  4. Memory Management – Exploring Rust's ownership model, borrowing, and lifetimes.
  5. Error Handling – Working with Result and Option types to handle errors.
  6. Concurrency in Rust – How Rust makes it safe and easy to write concurrent programs.
  7. Projects – A section with hands-on projects, such as the Guessing Game project.

Throughout this book, you'll also find exercises and practical examples to help reinforce your learning.

Contributing

This handbook is a personal project aimed at improving my own Rust skills. However, if you find any errors or want to contribute improvements, feel free to fork this repository, create a pull request, or open an issue.

Happy coding, and enjoy learning Rust!

How to Install Rust

Rust is a systems programming language focused on safety, speed, and concurrency. Follow the steps below to install Rust on your system.


The recommended way to install Rust is via rustup, a tool for managing Rust versions.

🧰 Prerequisites

  • Internet connection
  • Terminal or command prompt access

🖥️ Windows

  1. Download and run the rustup installer: https://win.rustup.rs
  2. Follow the on-screen instructions.
  3. After installation, restart your terminal and run:
    rustc --version
    

🐧 Linux

1.Open your terminal.

2.Install Rust with:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

3.Follow the prompt to install.

4.Restart Terminal and check:

rustc --version

🧪 Verify Installation After installing, you can check if everything works:

rustc --version
cargo --version

📦 variable — Rust Variables

In Rust, variables are used to store data for later use in your program. They are declared using the let keyword.

By default, Rust variables are immutable — meaning once a value is assigned, it cannot be changed. If you want to change the value of a variable later, you must explicitly make it mutable by adding mut before the variable name.

fn main() {
    let x = 5;//immutable variable
    println!("x is: {}", x);
}

🔎 Line-by-line breakdown:

  • let creates a new variable.

  • x is the variable name.

  • 5 is the integer value assigned.

  • println! is a macro that prints text to the console.

💡 If you're not sure what a macro is, don’t worry! For now, just remember that println! is used to display text in the console.

You might be wondering about the {} inside the string:
This is a placeholder. It gets replaced by the value of x when printed. So the line:

#![allow(unused)]
fn main() {
println!("x is: {}", x);
}

will output:

#![allow(unused)]
fn main() {
x is: 5
}

📦 mutable variable — Mutability in Rust

as i mentioned, variables are immutable by default. This means that once a value is assigned to a variable, it cannot be changed. However, sometimes you may need to modify a variable's value during execution. In such cases, you can declare the variable as mutable by using the mut keyword.

Declaring Mutable Variables

To declare a mutable variable in Rust, simply add mut before the variable name.

Example: Mutable Variables

fn main() {
    let mut x = 5; // mutable variable
    println!("x is: {}", x); // Output: x is: 5
    x = 10; // changing the value of x
    println!("Now, x is: {}", x); // Output: Now, x is: 10
}

🔎 Line-by-line breakdown:

  • let mut x = 5; — This declares a mutable variable x and assigns it the value 5.

  • x = 10; — This changes the value of x from 5 to 10.

Why Use Mutability?

  • Memory Safety: By default, Rust prevents accidental changes to variables, which helps avoid bugs and ensures that the program’s state is predictable.

  • Explicit Intent: Declaring variables as mut makes it clear in the code that the variable is intended to be modified. This improves code readability and reduces confusion.

Example: without Mutability

fn main() {
    let x = 5; // immutable variable
    println!("x is: {}", x); // Output: x is: 5
    // x = 10; // This would cause an error: cannot assign twice to immutable variable
}

💡 Key points to remember:

  • In Rust, variables are immutable by default.

  • Use the mut keyword to make a variable mutable if you plan to change its value after initial assignment.

  • You cannot change the value of an immutable variable.

Shadowing in Rust

In Rust, shadowing allows you to declare a new variable with the same name as a previous one. This new variable shadows the previous one, meaning the old variable is no longer accessible after the new one is introduced.

Shadowing is different from mutability, and it's a powerful feature for transforming data without needing mutability.

Example

fn main() {
    let x = 5;
    let x = x + 1; // shadows the previous x
    let x = x * 2; // shadows again

    println!("The value of x is: {x}"); // Output: 12
}

In this example:

  • First, x is 5.

  • Then x + 1 becomes 6, shadowing the original x.

  • Finally, x * 2 becomes 12, shadowing the second x.

Shadowing vs. Mutability

fn main() {
    let mut y = 5;
    y = y + 1; // OK because y is mutable

    let z = 5;
    let z = z + 1; // OK because this is shadowing
}

Key differences:

  • mut allows changing a variable's value.

  • Shadowing allows redefining a variable, even changing its type.

Changing Types with Shadowing

fn main() {
    let spaces = "   ";
    let spaces = spaces.len(); // Now spaces is a number!

    println!("Number of spaces: {spaces}"); // Output: 3
}

When to Use Shadowing

  • When transforming a variable step-by-step.

  • When changing the type of a variable (e.g., from &str to usize).

  • When you want to avoid making a variable mutable.

Summary

  • Shadowing lets you declare a new variable with the same name.

  • It's different from mut — it creates a new binding, not modifies the original.

  • You can change types with shadowing.

  • It's useful for cleaner, more functional-style code.

Constants

in Rust, constants are values that are bound to a name and are not allowed to change. They are evaluated at compile time and must have a type annotation. Constants can be declared in any scope, including the global scope, which makes them useful for values that many parts of the code need to know about.

Declaring Constants

Use the const keyword, followed by the name in SCREAMING_SNAKE_CASE, a type, and a value:

#![allow(unused)]
fn main() {
const MAX_POINTS: u32 = 100_000;
}

Rules for Constants

  • You must specify the type.

  • The value must be a constant expression, not the result of a function that runs at runtime.

  • Constants are valid for the entire lifetime of a program.

  • Naming convention is UPPERCASE with underscores.

const vs let

Featureconstlet
MutabilityAlways immutableMutable with mut
Type annotationRequiredInferred or optional
Evaluated atCompile timeRuntime
ScopeGlobal or localMostly used locally

Example:

const SECONDS_IN_MINUTE: u32 = 60;

fn main() {
    println!("One minute has {} seconds.", SECONDS_IN_MINUTE);
}

const vs static

Both const and static define values that live for the entire duration of the program, but:

  • const is inlined wherever it's used.

  • static has a fixed memory location and can be mutable (with unsafe).

#![allow(unused)]
fn main() {
static APP_NAME: &str = "RustyApp";
}