Basics
5 lessons · install · variables · types · control flow · functions
01. Getting Started with Rust (rustup · cargo · hello world)
Basics · Prerequisite: none
Rust is a systems programming language that guarantees memory safety at compile time. Without a garbage collector it delivers C/C++ class performance while preventing data races, null-pointer bugs, and use-after-free at the type-check phase. In this lesson you install the toolchain with rustup and run your first project with cargo.
02. Variables, Constants, Shadowing, Type Inference
Basics · Prerequisite: lesson 01
Rust variables are immutable by default. You add `mut` to make them mutable. This design improves multi-thread safety and code readability at the same time, and shadowing lets you reuse names without `mut`. This lesson also covers the difference between `let` and `const`, and when to annotate types vs. trust inference.
03. Basic Types (Integer, Float, bool, char, tuple, array)
Basics · Prerequisite: lesson 02
Rust's scalar types (i8/u8/i32/i64/f32/f64/bool/char) and compound types (tuple/array) — all in one lesson. The differences from other languages: integer overflow handling, char being a 4-byte Unicode scalar, and arrays having compile-time fixed size. (Heap-allocated dynamic vectors come in the next lesson cluster.)
04. Control Flow (if · loop · while · for · break-with-value)
Basics · Prerequisite: lesson 03
Rust's `if` is an expression — you can write `let x = if cond { 1 } else { 2 }`. This lesson covers `loop` / `while` / `for`, Rust-specific touches like attaching a value to `break`, labeled break / continue across nested loops, and `for` over ranges and iterators.
05. Functions, Expressions, Return Values, Doc Comments
Basics · Prerequisite: lesson 04
Defining functions with `fn name(arg: T) -> R { ... }`, the distinction between expressions and statements, returning implicitly via the last expression vs. explicit `return`, and `///` doc comments that turn into HTML via `cargo doc`. This lesson sets you up to write idiomatic functional Rust.
Ownership
5 lessons · ownership · borrowing · slices · lifetimes · String
06. The Three Rules of Ownership + move/copy
Ownership · Prerequisite: lessons 1-5
Ownership is the mechanism by which Rust guarantees memory safety without a garbage collector. Three rules suffice — each value has exactly one owner, the value is dropped when its owner goes out of scope, and assignment / argument passing moves ownership. This lesson covers move vs. copy, the meaning of Drop, and leads naturally into borrowing.
07. References and Borrowing (&T, &mut T, the borrow rules)
Ownership · Prerequisite: lesson 06
Borrowing lets you use a value without taking ownership — `&` for an immutable reference, `&mut` for a mutable one. The core rule is that at any moment you have either (N shared references) OR (1 exclusive mutable reference), never mixed. This is what blocks data races at compile time.
08. Slices — &str and &[T]
Ownership · Prerequisite: lesson 07
A slice is a reference view into part of a collection. `&str` is a view into a String or into a static string literal; `&[T]` is a view into a Vec or array. Slices supercharge function signatures and explain why `&str` is the idiomatic argument type rather than `String`.
09. Lifetimes — explicit 'a and elision rules
Ownership · Prerequisite: lesson 08
A lifetime is a compile-time marker for how long a reference is valid. You write them as `'a`, but most of the time the compiler infers them through elision rules. This lesson covers why lifetimes exist, when to write them by hand, and the meaning of `'static`.
10. String and &str in Depth — UTF-8, indexing
Ownership · Prerequisite: lesson 09
Rust strings are UTF-8 encoded. `String` is a heap-owned mutable buffer, `&str` is a reference view into part of it. This lesson explains why integer indexing is intentionally disallowed and how `.chars()` / `.bytes()` / `.char_indices()` give you explicit control over Unicode iteration.
Type system
4 lessons · struct · enum · pattern matching · traits
11. Structs (named, tuple, unit)
Type system · Prerequisite: ownership 1-5
Structs are the most basic user-defined type — they group values under meaningful names. Rust has three flavors: named structs with field names, tuple structs with positional fields, and unit structs with no data. Methods live in separate `impl` blocks.
12. Enums + Introducing Option<T>
Type system · Prerequisite: lesson 11
Rust enums are a different beast from C enums — each variant can carry **different data of different types**. They're true sum types. The most-used enum, `Option<T>` (`Some(T)` or `None`), is how Rust avoids the billion-dollar null-pointer mistake.
13. Pattern Matching (match · if let · while let)
Type system · Prerequisite: lesson 12
Rust's pattern matching is a different beast from switch in other languages — it does value matching plus destructuring plus guards plus ref/mut binding in one form. This lesson covers match arm patterns, guards, ranges, OR patterns, and the shorter `if let` / `while let`.
14. Traits (definition, implementation, default methods, trait objects)
Type system · Prerequisite: lesson 13
Traits are contracts that say "this type behaves like X." They play a role similar to Java/Kotlin interfaces or Haskell typeclasses — except Rust traits can also bundle default methods, associated types, and consts, which is what makes the chainable iterator API possible.
Error handling
4 lessons · Result/Option · ? operator · panic · thiserror
15. Working with Result<T,E> and Option<T>
Error handling · Prerequisite: types 1-4
Rust's error handling boils down to two enums — `Option<T>` for "may not exist" and `Result<T,E>` for "may fail." There's no try/catch; failure is encoded into types, so the compiler catches forgotten handling. This lesson covers conversions and helper methods between the two.
16. The ? Operator and Error Propagation
Error handling · Prerequisite: lesson 15
The `?` operator after a Result or Option expression means "return on failure immediately," turning nested match into a single line. Combined with the `From` trait it auto-converts error types as it propagates up the call stack.
17. panic! and Unrecoverable Errors
Error handling · Prerequisite: lesson 16
panic is Rust's way of saying "this is unrecoverable, stop now." Array bounds, integer division by zero, and `.unwrap()` on None all trigger panic automatically. This lesson covers how panic works, unwind vs. abort, and when to invoke panic on purpose.
18. Custom Error Types (thiserror, From)
Error handling · Prerequisite: lesson 17
Production libraries and services define concrete error enums so callers can branch on category — rather than rely on Box<dyn Error>. This lesson defines an error enum from scratch, implements Display, the Error trait, and From by hand, then collapses all of it with the thiserror crate.
Modern Rust
4 lessons · modules/Cargo · testing · concurrency · async
19. The Module System, Cargo, crates.io
Modern · Prerequisite: error 1-4
Once a Rust project grows you split code into modules and pull in external crates. This lesson covers the `mod` keyword and the file-split convention, `pub` visibility, `use` paths, declaring dependencies in Cargo.toml, and how to find and add packages from crates.io.
20. Unit Tests, Integration Tests, doctests
Modern · Prerequisite: lesson 19
Rust ships its test runner inside cargo. Add `#[test]` to a function and `cargo test` finds and runs it. This lesson covers unit tests (in a `mod tests` block), integration tests (under `tests/`), and doctests that automatically run code blocks in /// comments.
21. Threads, Channels, Arc/Mutex
Modern · Prerequisite: lesson 20
Rust calls its model "fearless concurrency" because the borrow checker prevents data races at compile time even across threads. This lesson covers std::thread, mpsc channels for thread-to-thread messages, and the Arc<Mutex<T>> pattern when you actually need shared state.
22. async/await + tokio intro
Modern · Prerequisite: lesson 21
async/await is the async programming model for handling many I/O-bound tasks efficiently. Rust ships the syntax but not a runtime — you pick one, and tokio is the de-facto standard. This lesson covers Futures, async fn, .await, the tokio runtime entry point, and join! for concurrent tasks.