All learning paths

Rust, from first principles

Why garbage collection and manual memory both cost you, then ownership, collections, traits, closures, concurrency and performance: the Rust you need to read and write real code.

58 articles · about 362 min of reading

0 of 58 read

Start with step 1

Why Rust?

  1. Step 1: GC Pauses and Latency: The Hidden Cost of High-Level LanguagesJava, Python, and JavaScript offer convenience, but garbage collection introduces unpredictable latency. Explore how runtime memory management affects performance in real systems.5 min
  2. Step 2: C Gives You Control, But at What Cost?C avoids garbage collection and gives manual memory control, but opens the door to dangerous bugs. Explore real-world memory issues and why they matter.7 min
  3. Step 3: Rust: Memory Safety Without Garbage CollectionRust gives you the performance of C with memory safety enforced at compile time. Learn how ownership and borrowing eliminate entire bug classes.9 min

Getting started

  1. Step 4: Getting Started with Rust: A Guide for BeginnersIntroduction to Rust for beginners, covering installation, basic syntax, and your first project.6 min
  2. Step 5: What is `clamp` in Rust, and when should you use it?What clamp does, why it panics on a swapped min and max, and how it differs from the saturating arithmetic it gets confused with.7 min

Ownership and memory

  1. Step 6: How does Rust ensure memory safety without a garbage collector?Ownership, borrowing and lifetimes give Rust memory safety at compile time, with no collector and no runtime pauses to budget for.6 min
  2. Step 7: Stack vs. Heap in Rust: Where Does Your Data Live?What actually decides whether a value lands on the stack or the heap in Rust, and what each choice costs you at runtime.4 min
  3. Step 8: How does ownership prevent memory leaks and data races?How the ownership rules close off memory leaks and data races before the program ever runs, and where they stop short.5 min
  4. Step 9: Mutable vs. immutable borrows: the two rulesThe two borrowing rules, why exclusivity is the one that matters, and what the borrow checker actually rejects.6 min
  5. Step 10: How does Rust prevent dangling pointer at compile time?Why a dangling pointer is a compile error in Rust rather than a crash in production, and how lifetimes make that check possible.5 min
  6. Step 11: What is &mut *x (reborrow) in Rust, and why does it freeze the original reference?A reborrow duplicates the reference, not the data, and freezes the original for its duration. What &mut *x really does.8 min
  7. Step 12: String vs. &str – Which to Use and When?String vs str in Rust, covering memory management, ownership, and when to use each type.6 min
  8. Step 13: Where do string literals (&str) live?String literals live in the binary's read-only data with a 'static lifetime — what that means for allocation, copying, and returning them.7 min
  9. Step 14: Why &str Won't Fit &String in Rust: Fun Fixes for String Mismatches!Why passing a &str where a &String is expected fails to compile, what deref coercion does and doesn't do, and how to fix the mismatch.5 min
  10. Step 15: What is the purpose of Box<T> in Rust?What Box<T> is for, what the extra indirection costs, and when a heap allocation is the right call rather than a reflex.6 min
  11. Step 16: How does Cow<'a, B> (Copy-on-Write) work in Rust?Cow<'a, B> lets a function borrow when it can and allocate only when it must. How copy-on-write works and when it pays for itself.6 min
  12. Step 17: Understanding the Drop Trait in RustHow the Drop trait works, when the destructor runs, and why implementing it by hand is rarer than it looks.6 min

Collections and iterators

  1. Step 18: Rust Vec::new() vs. with_capacity(): When to Use EachVec allocation strategies in Rust, comparing Vec::new() and Vec::with_capacity() for optimal performance.6 min
  2. Step 19: What is the difference between Box<[T]> and Vec<T>?Comparing Box<[T]> and Vec<T> differences in mutability, memory overhead, and performance implications for different use cases5 min
  3. Step 20: How do into_iter(), iter(), and iter_mut() differ?into_iter(), iter() and iter_mut() differ in what they hand you: the value, a shared reference, or an exclusive one.6 min
  4. Step 21: Implications of iterating over a Vec with .into_iter() instead of .iter()Understanding the differences between .into_iter() and .iter() when iterating over Vec, covering ownership implications and performance considerations6 min
  5. Step 22: Rust Operators & Iterators: Quick ReferenceEssential Rust operators, iterator differences, and Unicode handling you need to know.4 min
  6. Step 23: Rust's collect() Magic: Turning Iterators into Vecs, HashMaps, and Strings!How collect() decides what to build, what FromIterator asks of the target type, and how to steer it towards a Vec, a HashMap or a String.6 min
  7. Step 24: How do you remove duplicates from a Vec<T> where T: Eq + Hash?Efficient approaches to remove duplicates from Vec<T> where T: Eq + Hash, comparing HashSet-based and sort-based methods with performance analysis6 min
  8. Step 25: Vec::retain() Vs filtering with iter().filter().collect()?Comparing Vec::retain() in-place filtering with iter().filter().collect() for different filtering scenarios and performance implications6 min
  9. Step 26: Vec::drain() Vs Vec::truncate() or Vec::clear()?Understanding Vec::drain() functionality and comparing it with Vec::truncate() and Vec::clear() for different element removal scenarios6 min
  10. Step 27: Flatten a Vec<Vec<T>> into a Vec<T> using iteratorsFlattening Vec<Vec<T>> using iterators compared to manual concatenation, analyzing performance implications5 min

Traits and generics

  1. Step 28: Rust Traits vs. Java/C# Interfaces: Shared Behavior Done RightDiscussion on Rust traits vs Java/C# interfaces, covering dispatch mechanisms, compile-time behavior, and performance optimizations.6 min
  2. Step 29: Trait BoundsUsing trait bounds in Rust for type safety and performance in mathematical computations6 min
  3. Step 30: Trait bounds or dyn Trait? Static and dynamic dispatch comparedGenerics with a trait bound compile to static dispatch; dyn Trait compiles to a vtable lookup. What each costs, and how to choose.7 min
  4. Step 31: Making Traits Object-Safe for Rust's dyn Trait in Plugin SystemsUnderstanding object safety in Rust and refactoring traits for dynamic dispatch6 min
  5. Step 32: Supertraits: enforcing a hierarchy of behavioursLeveraging supertraits to establish behavior hierarchies and combining them with where clauses to optimize complex generic algorithms for performance and type safety7 min
  6. Step 33: ?Sized: writing one function for both sized and unsized typesUnderstanding the role of ?Sized bounds in Rust trait definitions and leveraging them to create flexible functions that work with both sized and unsized types efficiently7 min
  7. Step 34: Associated types vs. generics in a low-level I/O driver APIUtilizing associated types in Rust traits to design flexible, type-safe APIs for low-level I/O drivers and comparing advantages over generic type parameters7 min
  8. Step 35: Blanket implementations: one impl for every type that qualifiesEmploying blanket implementations in Rust to minimize code duplication for maintainable libraries7 min

Closures

  1. Step 36: Functions or Closures in Rust? Know the Difference!Functions vs closures in Rust, covering ownership, traits, lifetimes, and performance implications.6 min
  2. Step 37: What are the differences between Fn, FnMut, and FnOnce?Fn, FnMut and FnOnce aren't traits you pick — the compiler derives them from how the closure uses what it captured.6 min
  3. Step 38: What are move closures (move || { ... })? When are they necessary, and how do they interact with ownership?What move actually moves, when you genuinely need it (threads, returned closures, async blocks), and how it interacts with ownership.6 min
  4. Step 39: Understanding Rust Move Closures: A Guide for JavaScript DevelopersLearn how Rust move closures work compared to JavaScript closures - ownership, threading, and when to use the move keyword8 min
  5. Step 40: How do you specify a closure as a function parameter or return type?Taking and returning closures: when impl Fn is enough, when you need Box<dyn Fn>, and what each choice costs at the call site.6 min
  6. Step 41: Rust's Stateful Closures: Passing and Mutating Across Multiple CallsManaging stateful closures in Rust for repeated function calls6 min
  7. Step 42: Rust's Higher-Order Functions: Powering Flexible ClosuresExploring higher-order functions in Rust for functional programming patterns6 min
  8. Step 43: How do you store a closure in a struct?Storing closures in structs using generic parameters, trait objects, and lifetime annotations with Fn, FnMut, and FnOnce bounds6 min
  9. Step 44: How do you handle lifetimes when returning a closure that captures variables from its environment?Managing lifetimes when returning closures that capture variables, covering ownership transfer, lifetime annotations, and avoiding dangling references in Rust5 min
  10. Step 45: impl Fn() vs. Box<dyn Fn()>: Rust's Closure Dispatch ShowdownComparing static and dynamic dispatch for closures in Rust, focusing on performance and use cases7 min
  11. Step 46: Using closures versus regular functions ?Analyzing performance overhead of closures versus regular functions in Rust, covering static dispatch, heap allocation, and optimization scenarios5 min

Concurrency

  1. Step 47: How Rust's Ownership and Borrowing Ensure Safe ConcurrencyOwnership and borrowing rule out data races at compile time. What Send and Sync add, and why Rc can't cross a thread boundary.6 min
  2. Step 48: Deadlocks in C vs Rust: What Does Rust Really Prevent?Deadlocks aren't prevented by compilers—but Rust adds safety guarantees that make writing deadlock-prone code harder. Here's how it compares to C.7 min

Performance

  1. Step 49: Vec::push() in a loop vs. pre-allocating with Vec::with_capacity()?Comparing performance of Vec::push() in loops versus pre-allocating with Vec::with_capacity(), analyzing memory reallocation costs and optimization strategies6 min
  2. Step 50: Zero-Cost Abstractions: How Rust Optimizes Iterator ChainsLow-level optimization in Rust, focusing on iterator chains and zero-cost abstractions7 min
  3. Step 51: Avoiding heap allocation on a real-time pathLeveraging Rust's stack-based features like fixed-size arrays and Option to eliminate heap allocations in real-time systems for predictable, low-latency execution7 min
  4. Step 52: Rust's repr: Optimize Struct Memory for Cache EfficiencyLow-level memory optimization in Rust, covering repr attributes, cache efficiency, and performance trade-offs6 min
  5. Step 53: Align data structures to cache linesDesigning cache-aligned data structures in multi-threaded Rust applications to prevent false sharing and optimize performance for large dataset processing7 min
  6. Step 54: Boosting Rust Hot Loops: Slashing Branch MispredictionsLow-level optimization in Rust, focusing on minimizing branch mispredictions in performance-critical loops8 min
  7. Step 55: Instruction-Level Optimization: #[inline(always)]Strategic application of Rust's #[inline(always)] attribute for instruction-level optimization, covering effective usage patterns and risks of overuse6 min
  8. Step 56: SIMD in Rust: Optimizing Matrix MultiplicationLeveraging Rust’s SIMD support for accelerating matrix multiplication with considerations for portability and correctness8 min
  9. Step 57: Mastering Inline Assembly in Rust: When and How to Optimize SafelyLow-level optimization in Rust, focusing on using inline assembly for performance-critical tasks8 min
  10. Step 58: Profiling Rust: Tackling L1 Cache Misses with perf, Flamegraph, and CriterionLow-level optimization in Rust, focusing on profiling tools to identify and fix performance bottlenecks like L1 cache misses6 min