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:
- Introduction to Rust – A brief introduction to the language, its history, and why it’s so popular.
- Getting Started with Rust – How to install Rust and set up your development environment.
- Basic Syntax and Data Types – Covering variables, types, functions, and control flow.
- Memory Management – Exploring Rust's ownership model, borrowing, and lifetimes.
- Error Handling – Working with
ResultandOptiontypes to handle errors. - Concurrency in Rust – How Rust makes it safe and easy to write concurrent programs.
- 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.
📦 Installation (Recommended)
The recommended way to install Rust is via rustup, a tool for managing Rust versions.
🧰 Prerequisites
- Internet connection
- Terminal or command prompt access
🖥️ Windows
- Download and run the rustup installer: https://win.rustup.rs
- Follow the on-screen instructions.
- 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:
-
letcreates a new variable. -
xis the variable name. -
5is 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 variablexand assigns it the value5. -
x = 10;— This changes the value ofxfrom5to10.
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
mutmakes 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
mutkeyword 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,
xis5. -
Then
x + 1becomes6, shadowing the originalx. -
Finally,
x * 2becomes12, shadowing the secondx.
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:
-
mutallows 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
&strtousize). -
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
| Feature | const | let |
|---|---|---|
| Mutability | Always immutable | Mutable with mut |
| Type annotation | Required | Inferred or optional |
| Evaluated at | Compile time | Runtime |
| Scope | Global or local | Mostly 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:
-
constis inlined wherever it's used. -
statichas a fixed memory location and can be mutable (withunsafe).
#![allow(unused)] fn main() { static APP_NAME: &str = "RustyApp"; }