LearnLearn Rust Programming

Learn Rust Programming

A comprehensive course on Rust programming language covering memory safety, ownership, concurrency, and modern systems programming.

beginner
38 lessons
40 hours
CodeIdeal
Start with Introduction to Rust

On a deadline? Follow a plan.

The same lessons, mapped to your schedule.

All paths

Course Roadmap

6. Handling Errors

The judgment call that separates "fighting the compiler" from "writing Rust": when to panic, when to recover, how to propagate failure in one keystroke, and how to design error types that speak in your own words

0/3

7. Writing Reusable Code

The conceptual heart of the language: write code that works for any type, give types shared behavior through traits, and learn how Rust tracks how long references stay valid. The hardest stretch in this course — and, for most people, the most rewarding

0/3
Generics: Write It Once, for Every Type
The lesson where a piece of syntax you have been reading fluently since lesson 14 — those angle brackets wrapped around a single capital letter — finally gets a full name and a proper explanation. What generics actually are, why Option<T>, Result<T, E>, and Vec<T> all secretly are them, how to write your own generic functions, structs, and methods, and the genuinely delightful fact that none of it costs you a single nanosecond at runtime.
14m
Traits: One Idea Behind derive, PartialOrd, and From
The lesson where three separate mysteries — last lesson's PartialOrd bound, the #[derive(...)] attribute you have been writing without question since the structs lesson, and CountError's slightly awkward .map_err() calls from two lessons back — turn out to be the exact same idea, seen three times from three different angles. What a trait actually is, how default implementations and derive both quietly rest on it, and the genuinely satisfying moment two .map_err() calls disappear for good.
15m
Lifetimes: Telling the Compiler Which Reference You Meant
The lesson that answers the question the previous one ended on: a function takes two references and returns one of them, and for the first time in this course, the compiler refuses to guess which. The missing lifetime specifier error, read in full and explained in plain English; what 'a actually does (and the one big misconception about what it does NOT do); and the quiet elision rules that explain why every function before this one never needed any of this at all.
14m

11. Practical Rust

Now you can build things. Reading real input from arguments, environment variables, and files; turning your own structs into JSON and back with serde, your second external crate; and a small CLI tool that puts every lesson so far to work

0/3
Files and I/O: Arguments, Environment Variables, and Writing Files
Every file this course has opened — hello.txt, username.txt, count.txt — has had its name hardcoded directly into the source. Today that changes: std::env::args reads what was typed on the command line (an iterator, fed straight into the collect from the iterators lesson), std::env::var reads environment variables, and fs::write finally covers the other half of file I/O. Closes with Option::map and unwrap_or, tying Option directly to the Iterator methods from last lesson and the closures lesson before that.
13m
Serde and JSON: Turning Structs into Data
Lesson 4 added one external crate, rand, and used it once before derive, traits, or modules meant anything yet. This lesson adds the second: serde, plus its JSON half, serde_json. #[derive(Serialize, Deserialize)] is #[derive(Debug)] from the structs lesson, extended to a crate you did not write — turning any struct into a JSON string with serde_json::to_string and back with serde_json::from_str. Combined with fs::write and fs::read_to_string from the last lesson, a whole Vec<T> can be saved to disk and loaded back as one JSON file, with serde_json::Error sliding into Box<dyn Error> the same way every other error type has since the traits lesson.
13m
Building a CLI: A To-Do List That Uses Everything
The capstone of the core curriculum: a real, working command-line to-do list, task_cli. A Task struct with #[derive(Serialize, Deserialize)] from the serde-and-json lesson, load_tasks and save_tasks built from fs::read_to_string/fs::write and the env::var-style match from files-and-io, and a main() that dispatches add/list/done from env::args using the exact args.get(1).map(String::as_str) pattern the files-and-io lesson ended on. The list command is the iterators lesson's .enumerate() section, verbatim. Almost nothing new — everything used. Closes with a course-wide recap and an honest preview of the two ADVANCED sections ahead.
15m

12. Smart Pointers & Concurrency

ADVANCED. Box, Rc, and RefCell finally explain Box<dyn Error> from the propagating-errors lesson and unlock multiple owners and shared mutability — then threads, message passing, and the thread-safe Arc/Mutex versions of the same shapes

0/3
Smart Pointers: Box, Rc, and RefCell
Twelve lessons ago, Box<dyn Error> was introduced as "reads, for now, as some kind of error, built from an idea waiting for you further down this course." The traits lesson explained the dyn half: any type at all, decided at runtime. It never explained the Box. This lesson finally does: dyn Error has no size the compiler can know in advance, and Box<T> is always the same fixed size no matter what is inside, which is the entire reason Result<(), Box<dyn Error>> compiles. From there: Rc<T> for sharing read-only access to the same heap data from multiple owners, where Rc::clone is a counter bump rather than the ownership lesson's deep-copying clone, RefCell<T> for mutating through a shared reference by checking the borrowing rules at runtime instead of compile time (and panicking on purpose when they are broken), and Rc<RefCell<T>>, the shared-mutable-state shape the next lesson reaches for again across threads.
17m
Fearless Concurrency: Threads and Message Passing
The smart-pointers lesson ended by asking what happens once "multiple owners" means "multiple threads." Here is the answer: thread::spawn runs a closure on a real OS thread, and JoinHandle::join waits for it. Spawning a thread that touches a variable from main without move produces a real compiler error - "closure may outlive the current function" plus a note about outliving 'static - that is the closures lesson's move keyword and the lifetimes lesson's 'static prediction, both arriving at once. From there, std::sync::mpsc channels move ownership of values between threads one at a time, and Receiver<T> turns out to implement Iterator, so a spawned thread can stream results back with an ordinary for loop. Closes by previewing Arc<Mutex<T>>, the thread-safe cousin of last lesson's Rc<RefCell<T>>.
17m
Shared State: Mutex, Arc, and Send/Sync
The smart-pointers lesson promised it and the fearless-concurrency lesson named it: this lesson finally builds Arc<Mutex<T>>, the thread-safe replacement for Rc<RefCell<T>>. Starts by trying to send an Rc across a thread anyway and reading the real compiler error - "Rc<i32> cannot be sent between threads safely... the trait Send is not implemented" - which reuses thread::spawn's exact F: Send + 'static bound from the previous lesson's error. From there: Arc as Rc with an atomic counter, Mutex as RefCell's thread-safe cousin (.lock() instead of .borrow_mut(), returning a Result instead of panicking), a ten-thread counter that always prints Result: 10, and what that Result is actually for - a real lock-poisoning panic, captured live. Closes the Smart Pointers and Concurrency section by introducing Send and Sync by name.
18m

13. Going Further

ADVANCED, and the final stretch. async/await and Tokio - a second concurrency model, for waiting instead of running - followed by macro_rules!, the mechanism behind println!, vec!, and format! since lesson 6, and a closing map of where to go from here

0/3
Async Basics: async/await and Tokio
Smart Pointers & Concurrency covered Rust's model for doing many things at once, on real OS threads. This lesson covers the other kind of "at the same time": waiting on many things at once - network calls, timers, file reads - using async/await and the tokio runtime, an external crate (#[tokio::main]) since the standard library deliberately ships no executor. Two nearly-identical programs make the whole idea concrete: awaiting two 100ms/150ms waits back to back takes about 250ms, the sum - but tokio::join!-ing the same two futures takes about 150ms, the longer one - on a single thread, with no std::thread::spawn involved. Closes with tokio::spawn, async's answer to thread::spawn from the fearless-concurrency lesson, and why tasks scale to hundreds of thousands where OS threads can't.
17m
Macros 101: macro_rules!
Lesson 1's very first code example carried a one-line aside about println! - "a macro (note the !)" - never explained since, even as vec!, format!, write!, assert_eq!, panic!, and last lesson's tokio::join! piled up. This lesson finally explains it, starting from vec![], vec![1, 2, 3], and vec![5; 3] - three argument shapes no ordinary function could have - through macro_rules! arms (mirroring match), $x:expr captures (and the "sealed unit" precedence behavior that protects against C's classic macro bugs), repetition with $(...),* to reimplement a tiny vec!, and a recursive multi-arm my_min! whose entire expansion happens at compile time - the same zero-cost promise as generics' monomorphization, for syntax instead of types.
16m
Where to Go Next
The last lesson, and it teaches no new syntax. First, a look back: the threads that ran the length of this course - lesson 22's Box<dyn Error>, lesson 27/25's move and static-lifetime closures, lesson 33's Arc<Mutex<T>> preview, and lesson 1's very first ! - each picked up exactly when it mattered, because almost nothing here was taught in isolation. Then, forward: cargo clippy and cargo fmt, two commands that belong in every project from here on; a single unsafe block - raw pointers, dereferenced - the only unsafe code this course will ever show, named back in lessons 20 and 35 but never explained until now; and a map of the wider ecosystem (clap, anyhow, thiserror, reqwest, axum, rayon) showing which lesson prepared you for each. Closes with a final project extending lesson 32's task_cli, and a callback to lesson 9's "the compiler is teaching you."
14m