Rust Iterators Cookbook
- Preface
Chapter 1 — How Iterators Work
- The concept
- Recipe 1 — Iterating over a Vec without cloning
- Recipe 2 — Building an infinite iterator with next()
- Recipe 3 — Understanding why .map() alone does nothing
Chapter 2 — Choosing the Right Iterator
- The concept
- Recipe 4 — Reading a collection without consuming it
- Recipe 5 — Modifying elements in place
- Recipe 6 — Consuming a collection to produce a new one
- Recipe 7 — Understanding what
for x in vactually does
Chapter 3 — Lazy Evaluation
- The concept
- Recipe 8 — Confirming that adaptors are lazy
- Recipe 9 — Short-circuiting an expensive pipeline with take()
- Recipe 10 — Avoiding work with find() and position()
- Recipe 11 — Comparing lazy chains vs eager loops for clarity
Chapter 4 — Transforming Data
- The concept
- Recipe 12 — Transforming every element with map()
- Recipe 13 — Flattening nested collections with flat_map()
- Recipe 14 — Collapsing nested iterators with flatten()
- Recipe 15 — Pairing elements from two iterators with zip()
- Recipe 16 — Attaching an index with enumerate()
- Recipe 17 — Concatenating iterators with chain()
Chapter 5 — Filtering and Selecting
- The concept
- Recipe 18 — Keeping elements that match a condition with filter()
- Recipe 19 — Filtering and transforming in one step with filter_map()
- Recipe 20 — Taking the first N elements with take() and take_while()
- Recipe 21 — Skipping elements with skip() and skip_while()
- Recipe 22 — Sampling every Nth element with step_by()
Chapter 6 — Aggregating and Consuming
- The concept
- Recipe 23 — Collecting into different container types
- Recipe 24 — Reducing to a single value with fold()
- Recipe 25 — Using reduce() when no initial value is needed
- Recipe 26 — Summing and counting
- Recipe 27 — Short-circuiting checks with any() and all()
- Recipe 28 — Consuming for side effects with for_each()
Chapter 7 — Composing Pipelines
- The concept
- Recipe 29 — Building a log processing pipeline
- Recipe 30 — Parsing a CSV with a fallible pipeline
- Recipe 31 — Deduplicating and normalizing a sequence
- Recipe 32 — Grouping elements with fold() and a HashMap
- Recipe 33 — Flattening a pipeline with nested Options and Results
- Recipe 34 — Knowing when not to use a pipeline
Chapter 8 — Implementing Iterator from Scratch
- The concept
- Recipe 35 — Iterating over fields of a struct
- Recipe 36 — An iterator with internal state
- Recipe 37 — A borrowing iterator with a lifetime
- Recipe 38 — Iterating over a recursive data structure
- Recipe 39 — Implementing size_hint() for better collect() performance
Chapter 9 — Creating Custom Adaptors
- The concept
- Recipe 40 — A simple stateless adaptor
- Recipe 41 — A stateful adaptor with an accumulator
- Recipe 42 — An adaptor that transforms and filters simultaneously
- Recipe 43 — A generic adaptor with full type flexibility
Chapter 10 — Specialized Iterator Traits
- The concept
- Recipe 44 — Iterating in reverse with DoubleEndedIterator
- Recipe 45 — Implementing DoubleEndedIterator for a custom type
- Recipe 46 — Peeking at the next element without consuming it
- Recipe 47 — Implementing FusedIterator for correctness
- Recipe 48 — Using size_hint() and len() downstream
Chapter 11 — Performance and Zero-Cost Abstractions
- The concept
- Recipe 49 — Verifying zero-cost with a benchmark
- Recipe 50 — Avoiding intermediate allocations
- Recipe 51 — Choosing between iterator chains and for loops for performance
- Recipe 52 — When collect() is expensive and what to do instead
- Recipe 53 — Exploiting SIMD via iterator chains
- Recipe 54 — Profiling an iterator pipeline
Chapter 12 — Parallel Iterators with Rayon
- The concept
- Recipe 55 — Drop-in parallelism with par_iter()
- Recipe 56 — Parallel aggregation with reduce() and sum()
- Recipe 57 — Parallel flat_map and collecting into a HashMap
- Recipe 58 — Knowing when not to use Rayon
Chapter 13 — Async Iterators with Stream
- The concept
- Recipe 59 — Creating a Stream from a Vec and consuming it
- Recipe 60 — Streaming lines from a file
- Recipe 61 — Consuming a channel as a Stream
- Recipe 62 — Transforming a Stream with map() and then()
- Recipe 63 — Merging multiple Streams
- Recipe 64 — Stream vs Iterator: when to use which
Chapter 14 — Error Handling in Pipelines
- The concept
- Recipe 65 — Fail fast: stop at the first error
- Recipe 66 — Collect all errors before reporting
- Recipe 67 — Skip errors silently
- Recipe 68 — Using the ? operator inside closures
- Recipe 69 — Transforming error types mid-pipeline
- Recipe 70 — Building a pipeline that returns Result
Chapter 17 — The itertools Crate
- The concept
- Recipe 71 — Grouping consecutive elements with chunk_by()
- Recipe 72 — Sliding windows with tuple_windows()
- Recipe 73 — Cartesian product with cartesian_product()
- Recipe 74 — Combinations and permutations
- Recipe 75 — Interleaving and merging sequences
- Recipe 76 — Collecting into multiple collections at once with partition_map()
- Recipe 77 — Unique elements with unique() and unique_by()
- Recipe 78 — Formatting with join() and format_with()
- When to reach for itertools
Chapter 15 — Exercises
- Chapter 1 — How Iterators Work
- Chapter 2 — Choosing the Right Iterator
- Chapter 3 — Lazy Evaluation
- Chapter 4 — Transforming Data
- Chapter 5 — Filtering and Selecting
- Chapter 6 — Aggregating and Consuming
- Chapter 7 — Composing Pipelines
- Chapter 8 — Implementing Iterator
- Chapter 9 — Custom Adaptors
- Chapter 14 — Error Handling in Pipelines
- Chapter 11 — Performance
Chapter 16 — When Not to Use Iterators
- When the control flow has multiple exit conditions
- When two cursors move independently through the same sequence
- When you need to mutate while inspecting neighbors
- When the pipeline becomes unreadable
- When you need random access mid-iteration
- When you are debugging
- Summary