Learn
Foundations
- Hello, Rust: Your first programs. What fn main is, how println! prints text, and how to read the compiler's (very helpful) error messages.
- Variables and Mutability: Give values names with let. Why Rust variables can't change unless you say mut, how shadowing works, what types and constants are, and how Rust teams name things.
- Numbers, Booleans and Characters: Rust's basic types up close. Integer sizes and what happens when they overflow, floating-point numbers, converting between types with as, true/false logic, and Unicode characters.
- Functions: Split programs into named, reusable pieces. Parameters, return values, why the last expression is the result, how statements and blocks work, and returning early.
- Control Flow: Make decisions with if and else, and repeat work with loop, while and for. Includes if as an expression, ranges, break and continue, nested loops and loop labels.
- Tuples, Arrays and a First Vec: Group values together. Tuples bundle a few values of any type, arrays hold a fixed row of values of one type, and Vec is a list that grows while the program runs.
- Working with Text: A first look at Rust's two string types, String and &str, and the everyday tools for text. Build strings, join them, measure them, change case, search, replace, trim and compare.
- Reading Input: Make programs react to data. Read lines from standard input, turn text into numbers with parse, process input line by line or all at once, split lines into values, and handle bad input without crashing.
Ownership
- Ownership: Where your data lives (stack and heap), who is responsible for freeing it, and why assigning a String moves it. The rules that make Rust memory-safe without a garbage collector.
- Borrowing: Use a value without taking ownership of it. References (&T and &mut T), the "many readers or one writer" rule, and how the borrow checker makes dangling pointers and data races impossible.
- Slices: Borrow part of a string, array or vector without copying it. String slices (&str), array and vector slices (&[T] and &mut [T]), and why &str and &[T] are the parameter types experienced Rust programmers reach for.
Structuring data
- Structs: Build your own types by grouping related values under one name. Define structs, create and change them, pass them to functions, use tuple structs as newtypes, and print them with #[derive(Debug)].
- Methods: Attach behavior to your own types with impl blocks. Write methods that read (&self), change (&mut self) or consume (self) a value, constructors like new, getters that protect your rules, and chains of method calls.
- Enums and Option: Model values that are one of several kinds. Define enums with and without data, take them apart with exhaustive match, handle missing values with Option instead of null, use if let, let...else and matches!, and make invalid states unrepresentable.
- Patterns and matching: Patterns check the shape of a value and take it apart in one move: literals, ranges, alternatives, guards, @ bindings, destructuring structs, tuples, nested enums and slices, while let, and where each kind of pattern is allowed.
- Vectors: Vec<T>, the growable list you'll use more than any other collection: adding and removing, safe access with get, the three ways to loop, sorting, deduplicating, searching, and vectors of your own structs.
- HashMaps and sets: Look things up by key with HashMap, count with the entry API, keep unique values with HashSet, and combine sets. Plus why hash order changes from run to run, and when to reach for BTreeMap and BTreeSet instead.
- Strings in depth: How Rust text really works: UTF-8 bytes versus chars, why s[0] doesn't compile, slicing safely, splitting and parsing lines, trimming and searching, building strings efficiently, and formatting aligned tables with Display and Debug.
Errors and abstraction
- Error Handling with Result: Rust has no exceptions. A failure that can happen in normal use is a value of type Result, and the ? operator passes it up to the caller. Learn when to panic, when to return an error, and the combinators that keep error handling short.
- Custom Error Types: Design error types callers can act on. Error enums, Display messages, the Error trait, Box<dyn Error>, From conversions that let ? do the work, error chains, when to panic, and a first look at the thiserror and anyhow crates.
- Generics: Write a function or a type once and use it with many types. Generic functions, trait bounds like T: PartialOrd + Copy, generic structs, enums and impl blocks, why generics cost nothing at run time, and const generics for arrays of any length.
- Traits: Shared behavior. Define your own traits, give them default methods, accept "anything that can do X" with trait bounds and impl Trait, implement Display, and let derive write the standard traits for you.
- Standard Library Traits: The traits that make your types feel built in. Convert with From, TryFrom and FromStr, use operators like + and [] on your own types, sort them with Ord, give them defaults, and run cleanup code with Drop.
- Lifetimes: How Rust proves every reference points at something still alive. Read lifetime errors calmly, annotate functions and structs that hand out references, know the elision rules, and know when returning owned data is the better answer.
- Trait Objects: Different types behind one interface, chosen at run time. Store a mix of types in one Vec with Box<dyn Trait>, pass &dyn Trait, build plugin registries, understand static vs dynamic dispatch and dyn compatibility, and decide between enums and trait objects.
Idiomatic Rust
- Closures: Small anonymous functions that can use the variables around them. Closure syntax, capturing by borrow, mutable borrow and move, the Fn/FnMut/FnOnce traits, and passing closures into and out of functions.
- Iterators: How professional Rust processes data. The Iterator trait and next, adapters like map, filter, zip and windows, consumers like sum, fold and collect, laziness, collecting into Result, and writing your own iterator.
- Modules, Crates and Cargo: Organizing code that grows. mod blocks, privacy with pub, paths and use, re-exports, struct field privacy, splitting a crate into files, and Cargo packages with dependencies, semver, features, workspaces and publishing.
- Smart Pointers: Box for heap values and recursive types like lists and trees, Deref and Drop, Rc for shared ownership, RefCell and Cell for changing data behind a shared reference, and Weak for parent links that don't leak.
- Testing: Write tests that actually catch bugs. #[test] and the assert macros, edge cases and planted bugs (mutants), #[should_panic] and tests returning Result, fixing bugs test-first, and how unit, integration and doc tests are organized.
Concurrency and async
- Threads: Do several things at once with std::thread. Spawn and join threads, move data into them, borrow local data with scoped threads, see how Send and Sync rule out data races at compile time, handle panicking workers, and let rayon spread work over every core.
- Sharing data between threads: The tools threads use to work together. Channels to pass messages, Arc to share data, Mutex and RwLock to change it safely, atomics for counters and flags, OnceLock and LazyLock for global state, and how to avoid deadlocks.
- Async Rust with Tokio: Handle thousands of waiting tasks on a few threads. Futures and .await, the Tokio runtime, running futures concurrently with join!, spawning tasks, async channels, racing futures with select! and timeouts, and when to choose async over threads.
Advanced Rust
- Advanced Traits: The trait features library authors use every day. Associated types, operator traits, supertraits, blanket impls, newtypes and the orphan rule, and typestate APIs that turn wrong calls into compile errors.
- Macros: Code that writes code. Build your own macro_rules! macros (from one-liners to repetition, recursion and small DSLs), debug them, and see what procedural macros like derive(Debug) and derive(Serialize) generate.
- Unsafe Rust: What unsafe really allows, how to wrap it in safe APIs with SAFETY comments, calling C through FFI, global state without static mut, finding undefined behavior with Miri, and why most code at work never needs unsafe at all.
- Performance: Honest, measured performance work. Pick the right algorithm and collection first, then cut needless clones and allocations, lean on zero-cost iterators and Cow, and learn the release builds, benchmarks and profilers that tell you where the time really goes.
Rust at work
- JSON and Serialization with serde: Turn your structs and enums into JSON and back with serde and serde_json, shape the JSON with attributes, work with dynamic JSON, and handle bad input the way production code does.
- Error Handling at Work with thiserror and anyhow: The two crates nearly every Rust team uses for errors. thiserror for precise library errors, anyhow for applications, context that explains what went wrong, and a main that reports failures properly.
- Building Command-Line Tools: Write real command-line programs. Arguments and flags, exit codes and stderr, reading files and standard input, and the Config/run structure every Rust CLI uses, plus how clap does the parsing for you.
- Web Services and JSON APIs: How HTTP APIs work and how to build one in Rust. Requests and responses, routing, JSON with serde, errors as status codes, shared state, and testing handlers, then the same API in axum.
- Design Patterns and Idioms: The patterns experienced Rust developers reach for, and the ones reviewers ask for. Builders, newtypes, state machines, conversions, RAII guards and returned iterators, ending with a real code-review refactor.
- Debugging, Docs and Tooling: The tools around the code. Debug with dbg! and eprintln!, read panics and backtraces, use a debugger and logging, document with rustdoc, satisfy clippy and rustfmt, and wire it all into CI.
Algorithms and data structures
- Stacks, Queues, Heaps and Ordered Maps: The rest of std::collections. Stacks with Vec, queues with VecDeque, priority queues with BinaryHeap, range queries with BTreeMap, why LinkedList is rare, and how to pick the right collection for a job.
- Searching, Sorting and Classic Techniques: How fast is your code? Big-O, linear and binary search, sorting (and writing your own merge sort), custom orderings, and the interview workhorses two pointers, sliding window and prefix sums.
- Recursion and Dynamic Programming: Functions that call themselves, backtracking through choices, and dynamic programming (memoization with HashMap and bottom-up tables) for the classic problems: coin change, longest common subsequence, edit distance, grid paths and knapsack.
- Graphs and Trees: Model networks, dependencies and maps as graphs. Adjacency lists, BFS for shortest hops, DFS with recursion or a stack, topological sort, Dijkstra with a BinaryHeap, binary trees with Option<Box<Node>>, and union-find.
Capstone
- Capstone: Real Tickets: Six workplace tickets that combine everything in the course. Parse logs with FromStr and an error enum, build a traffic report, validate orders with thiserror, check a deploy config with serde, model an order workflow as a state machine, and refactor code for review.