Step 1 • Setup
Rust Toolchain — rustup, cargo, and the Ecosystem beginner Install Rust with rustup (the official toolchain manager) — it manages multiple Rust versions (stable, beta, nightly) and cross-compilation targets. Understand Cargo (Rust's build system and package manager) — cargo new, cargo build, cargo run, cargo test, cargo fmt, cargo clippy (linter), cargo doc. The Cargo.toml is your project manifest — dependencies, features, workspace config. Crates.io is the package registry. Use rust-analyzer for IDE support. Know the difference between bin and lib crates.
Language Rust 3h Step 2 • Foundations
Syntax, Variables, and Control Flow beginner Rust is expression-oriented — almost everything returns a value. Learn variable bindings (let x = 5 — immutable by default, let mut for mutable), constants (const MAX: u32 = 100), shadowing (re-binding a name), scalar types (i8..i128, u8..u128, f32/f64, bool, char), compound types (tuples, arrays), if/else as expressions, loop/while/for, ranges (0..10, 0..=10), and match. Understand that Rust has no null — None is explicit through Option<T>. Semicolons matter — expressions with ; are statements, without ; return a value.
Language Rust 6h Step 3 • Foundations
Ownership, Borrowing, and the Borrow Checker intermediate Ownership is Rust's killer feature — it enables memory safety without a garbage collector. The three rules: each value has one owner, there can only be one owner at a time, the value is dropped when the owner goes out of scope. Learn moves vs copies (types implementing Copy are copied, others are moved), references (&T) for borrowing without taking ownership, mutable references (&mut T — only one at a time), and slices (&str, &[T]). The borrow checker enforces these rules at compile time. Most beginner frustration is fighting the borrow checker — understand why, not just how.
Language Rust 10h Step 4 • Foundations
Structs, Enums, and Pattern Matching intermediate Structs group related data — named fields, tuple structs, unit structs. Define methods with impl blocks (self, &self, &mut self). Enums are algebraic data types — each variant can hold different data (Option<T>, Result<T, E> are enums). Match is exhaustive pattern matching — must handle every variant, can destructure, can have guards (if x > 0). if let and while let for concise single-pattern matching. The power of Rust enums over C unions or Java enums: they carry data and the compiler forces you to handle all cases.
Language Rust 8h Step 5 • Foundations
Error Handling with Result and the ? Operator intermediate Rust has no exceptions. Recoverable errors use Result<T, E> — Ok(value) or Err(error). The ? operator propagates errors — if Err, return early from the current function (the function must return Result). Unrecoverable errors use panic! (also triggered by out-of-bounds indexing, unwrap() on None/Err). Define custom error types with thiserror (derive macro for std::error::Error) or use anyhow for application-level error handling (context chaining with .context()). Know when to use which: thiserror for library crates, anyhow for binary crates.
Language Rust 6h Step 6 • Standard Library
Collections — Vec, HashMap, String, and Slices intermediate Rust's standard collections live on the heap. Vec<T> — growable array (push, pop, index, iter, retain, sort, dedup). HashMap<K, V> — entry API for conditional insert (entry().or_insert()), iteration in arbitrary order. String vs &str — String is owned heap-allocated UTF-8, &str is a borrowed slice. String methods (split, trim, contains, chars, bytes, parse). VecDeque for efficient front/back operations. HashSet for unique values. BTreeMap for sorted keys. Understand clone() cost and when to use it.
Language Rust 6h Step 7 • Type System
Traits — Shared Behavior and Polymorphism intermediate Traits define shared behavior — like interfaces but more powerful. Define traits (trait Summary { fn summarize(&self) -> String; }), implement traits for types (impl Summary for Article), and use trait bounds (fn notify(item: &impl Summary) or fn notify<T: Summary>(item: &T)). Important standard traits: Display, Debug, Clone, Copy, Iterator, From/Into, Default, PartialEq/Eq, Hash. impl Trait in return position for closures. dyn Trait for dynamic dispatch (heap-allocated, runtime). Understand object safety rules for dyn Trait.
Language Rust 8h Step 8 • Type System
Generics and Lifetimes advanced Generics let you write code that works for multiple types (fn largest<T: PartialOrd>(list: &[T]) -> T). Structs and enums can be generic (struct Stack<T>). Rust monomorphizes generics at compile time — zero runtime cost. Lifetimes annotate how long references live — the borrow checker uses them to prevent dangling references. Syntax: fn longest<'a>(x: &'a str, y: &'a str) -> &'a str. The compiler can often infer lifetimes (elision rules). Lifetime annotations in structs holding references. 'static lifetime. Don't add lifetimes unless the compiler asks — understand the error first.
Language Rust 10h Step 9 • Functional Patterns
Closures and the Iterator Pattern intermediate Closures capture their environment — Fn (borrows), FnMut (borrows mutably), FnOnce (consumes). They're first-class: pass to functions, return from functions, store in structs. The Iterator trait is central to idiomatic Rust — map, filter, reduce/fold, take, skip, zip, enumerate, chain, collect (into Vec, HashMap, String). Iterators are lazy (no work until consumed). Prefer iterator chains over for loops for their composability. adapt iterators: iter() (borrows), iter_mut() (mut borrows), into_iter() (owns). Use rayon for parallel iterators.
Language Rust 7h Step 10 • Memory Management
Smart Pointers — Box, Rc, RefCell, Arc, Mutex advanced Smart pointers own memory and enforce rules at compile or runtime. Box<T> allocates on the heap (recursive types, large values, trait objects). Rc<T> — reference counting for single-threaded shared ownership (clone increments the count, drop decrements). RefCell<T> — interior mutability (runtime borrow checking, can mutate through shared reference). Arc<T> — atomic reference counting for multi-threaded shared ownership. Mutex<T> — mutual exclusion for safe mutation across threads. Common patterns: Arc<Mutex<T>> for shared mutable state, Rc<RefCell<T>> for single-threaded graphs.
Language Rust 8h Step 11 • Concurrency
Fearless Concurrency — Threads and Channels advanced Rust's ownership model makes data races impossible at compile time — this is 'fearless concurrency'. Spawn OS threads with std::thread::spawn (takes an ownership-capturing closure), use thread::join() to await. Communicate via channels — std::sync::mpsc (multi-producer, single-consumer): Sender, Receiver, channel(). Share state with Arc<Mutex<T>>. The Send trait marks types safe to send across threads, Sync marks types safe to share references across threads — the compiler enforces this. Understand deadlocks (still possible) and how to avoid them with lock ordering.
Language Rust 7h Step 12 • Async
Async Rust with Tokio advanced Async Rust enables concurrent I/O without OS threads. async fn returns a Future — a value representing a deferred computation. .await pauses the current task until the future is ready. Futures are lazy — they do nothing until polled by an executor. Tokio is the most popular async runtime: tokio::main, tokio::spawn (lightweight tasks), tokio::time::sleep, tokio::fs, tokio::net. async-std is an alternative. Understand why async requires a runtime (unlike Go's built-in scheduler), the difference between concurrency and parallelism in async, and why CPU-bound work should use spawn_blocking.
Backend Rust 9h Step 13 • Testing
Testing — Unit, Integration, and Doc Tests intermediate Testing is built into Rust — no external framework needed. Unit tests live in the same file in a #[cfg(test)] module, annotated with #[test]. Integration tests live in a tests/ directory and test the public API. Doc tests are examples in documentation comments (///) that are compiled and run — keep docs correct by example. Use assert!, assert_eq!, assert_ne!, should_panic. The criterion crate for benchmarks (cargo bench). mockall for mocking traits. proptest for property-based testing — generates random inputs to find edge cases.
Language Rust 6h Step 14 • Metaprogramming
Macros — Metaprogramming in Rust advanced Rust macros generate code at compile time — they're invoked with a ! (println!, vec!, assert!). Two types: declarative macros (macro_rules! — pattern matching on token trees, great for reducing repetitive code) and procedural macros (operate on the AST — three subtypes: derive macros (#[derive(Debug, Clone, Serialize)] — most common), attribute macros (#[tokio::main], #[test]), and function-like macros (sql!, html!)). Derive macros are used constantly in Rust — serde's #[derive(Serialize, Deserialize)], the-error's #[derive(Error)], and Axum's extractors all use them. Write a simple macro_rules! before diving into proc macros (which require a separate crate). syn and quote are the essential proc macro libraries.
Language Rust 6h Step 15 • Applications
Building CLI Tools with clap intermediate Rust is excellent for CLI tools — fast startup, single binary, cross-compile. clap is the CLI argument parser — derive API (#[derive(Parser)]) generates a CLI from a struct. Learn subcommands, flags, options, positional arguments, validation, and auto-generated help text. indicatif for progress bars and spinners. colored or owo-colors for terminal colors. dialoguer for interactive prompts. env_logger or tracing for logging. Build cross-platform binaries with cross (Docker-based cross-compilation). Distribute via cargo install, Homebrew, or GitHub Releases.
Backend Rust 5h Step 16 • Applications
Web APIs with Axum advanced Axum is the leading web framework for Rust — built on Tokio and Tower, composable via middleware. Learn routing (get, post, Router::nest), extractors (Path, Query, Json, State — typed request data), handlers (async functions returning IntoResponse), shared state with Arc<AppState>, error handling with custom response types, and middleware with tower-http (CORS, logging, compression, rate limiting). Use sqlx for async database queries (compile-time checked SQL). Serde for JSON serialization. Deploy with Docker.
Backend Rust 8h Step 17 • Systems Programming
Unsafe Rust and FFI advanced unsafe blocks allow operations the borrow checker can't verify: dereferencing raw pointers (*const T, *mut T), calling unsafe functions, implementing unsafe traits, accessing mutable static variables, and reading union fields. Unsafe is necessary at system boundaries and for performance-critical code. Foreign Function Interface (FFI) calls C code from Rust (extern "C") or exposes Rust to C (pub extern "C" + #[no_mangle]). Use bindgen to auto-generate Rust bindings from C headers. cbindgen to generate C headers from Rust. Encapsulate unsafe in safe abstractions — the public API should always be safe.
Language Rust 6h Step 18 • Production
Production — Performance, Profiling, and Deployment advanced Rust is fast by default, but production requires deliberate optimization. cargo build --release enables full optimizations (LLVM O3, LTO). Profile with flamegraph (cargo flamegraph), perf, or Instruments (macOS). Reduce binary size with strip, opt-level='z', LTO, and panic=abort. Use divan or criterion for micro-benchmarks. Feature flags (features in Cargo.toml) for optional functionality. cargo audit to check dependencies for known vulnerabilities. cargo deny for license compliance. Publish to crates.io with cargo publish. Use GitHub Actions for CI (cargo test, cargo clippy, cargo audit).
Backend Rust 7h