Iterator Basics

Back

Loading concept...

🚂 Rust Iterators: The Magic Assembly Line

Imagine a factory where tiny robots only do work when you actually need the product!


🎬 The Story of the Lazy Factory

Picture a chocolate factory with a long assembly line. But this isn’t a normal factory—it’s a lazy factory! The machines only turn on when someone is actually waiting to eat the chocolate at the end.

That’s exactly how Rust iterators work!

  • The assembly line = Iterator
  • The machines along the line = Iterator adaptors (like map and filter)
  • Someone eating chocolate at the end = Consuming the iterator

Let’s explore this magical factory!


🎯 What is the Iterator Trait?

Think of the Iterator trait as a promise. Any collection that makes this promise says:

“I can give you items one at a time, until I run out!”

The Simple Rule

Every iterator knows how to do ONE thing: give you the next() item.

// A simple iterator example
let numbers = vec![1, 2, 3];
let mut iter = numbers.iter();

println!("{:?}", iter.next());
// Some(1)
println!("{:?}", iter.next());
// Some(2)
println!("{:?}", iter.next());
// Some(3)
println!("{:?}", iter.next());
// None (empty!)

Why Some and None?

  • Some(value) = “Here’s your next item!”
  • None = “Sorry, I’m all out!”

It’s like a vending machine. You press the button, and either a snack comes out (Some), or it’s empty (None).


😴 Lazy Evaluation: The Sleepy Workers

Here’s the magic secret of Rust iterators:

Nothing happens until you ask for it!

The Lazy Factory Analogy

Imagine you tell the factory:

  1. “Paint all chocolates red”
  2. “Remove the small ones”
  3. “Wrap them in gold paper”

In a normal factory, workers immediately start doing ALL of this.

In a lazy factory (Rust iterators), workers just… sit there. They only start when someone says “Give me a chocolate!”

let numbers = vec![1, 2, 3, 4, 5];

// This does NOTHING yet!
let lazy_work = numbers.iter()
    .map(|x| x * 2)
    .filter(|x| *x > 4);

// Still nothing happened!
println!("Workers are sleeping...");

// NOW the work happens!
for num in lazy_work {
    println!("{}", num);
}
// Prints: 6, 8, 10

Why is Lazy Good?

  1. Saves energy - Don’t do work you don’t need
  2. Works with infinite things - You can have an endless assembly line!
  3. Faster - Only processes what you actually use

🔧 Iterator Adaptors: The Machine Add-Ons

Iterator adaptors are like adding new machines to your assembly line. Each machine takes items in, does something, and passes them along.

The cool part? You can chain them together!

graph TD A["📦 Original Items"] --> B["🔧 Adaptor 1: map"] B --> C["🔧 Adaptor 2: filter"] C --> D["📦 Final Items"]

Key Adaptors

Adaptor What It Does Analogy
map Transform each item Painting machine
filter Keep only some items Quality checker

Let’s explore each one!


🎨 The map Method: The Transformation Machine

map takes every item and transforms it into something else.

Real-Life Analogy

Imagine a machine that takes plain donuts and adds frosting to each one:

  • Plain donut goes IN → Frosted donut comes OUT
  • Every single donut gets the same treatment
let plain_donuts = vec![1, 2, 3];

// Add 10 "frosting units" to each
let frosted = plain_donuts.iter()
    .map(|donut| donut + 10);

// Collect the results
let result: Vec<i32> = frosted.collect();
println!("{:?}", result);
// [11, 12, 13]

More Examples

Double everything:

let nums = vec![1, 2, 3];
let doubled: Vec<i32> = nums.iter()
    .map(|x| x * 2)
    .collect();
// [2, 4, 6]

Convert to strings:

let nums = vec![1, 2, 3];
let strings: Vec<String> = nums.iter()
    .map(|x| x.to_string())
    .collect();
// ["1", "2", "3"]

The Golden Rule of map

Same number of items IN = Same number of items OUT

map never removes items. It just changes them!


🚦 The filter Method: The Bouncer

filter is like a bouncer at a club. It looks at each item and decides:

  • ✅ “You pass the test, come in!”
  • ❌ “Nope, you’re out!”

Real-Life Analogy

A quality checker at a fruit factory:

  • Only apples bigger than a certain size get through
  • Small apples are rejected
let apples = vec![3, 7, 2, 8, 1, 9];

// Only keep apples bigger than 5
let big_apples: Vec<&i32> = apples.iter()
    .filter(|apple| **apple > 5)
    .collect();

println!("{:?}", big_apples);
// [7, 8, 9]

The Test Function

filter needs a function that returns true or false:

  • true → Keep this item!
  • false → Throw it away!

Keep only even numbers:

let nums = vec![1, 2, 3, 4, 5, 6];
let evens: Vec<&i32> = nums.iter()
    .filter(|x| **x % 2 == 0)
    .collect();
// [2, 4, 6]

Keep only positive numbers:

let nums = vec![-3, -1, 0, 2, 5];
let positives: Vec<&i32> = nums.iter()
    .filter(|x| **x > 0)
    .collect();
// [2, 5]

⛓️ Chaining: Build Your Dream Factory!

The REAL power comes from chaining adaptors together!

let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

let result: Vec<i32> = numbers.iter()
    .filter(|x| **x % 2 == 0)  // Keep evens
    .map(|x| x * 10)            // Multiply by 10
    .collect();

println!("{:?}", result);
// [20, 40, 60, 80, 100]

What Just Happened?

graph TD A["[1,2,3,4,5,6,7,8,9,10]"] --> B["filter: keep evens"] B --> C["[2, 4, 6, 8, 10]"] C --> D["map: multiply by 10"] D --> E["[20, 40, 60, 80, 100]"]

Step by step:

  1. Start with 1-10
  2. filter keeps only even numbers: 2, 4, 6, 8, 10
  3. map multiplies each by 10: 20, 40, 60, 80, 100

🏁 Consuming Iterators: Starting the Factory

Remember: iterators are lazy! To actually get results, you need to consume them.

Common Consumers

Consumer What It Does
collect() Gather all items into a collection
for loop Process each item one by one
sum() Add all numbers together
count() Count how many items
let nums = vec![1, 2, 3, 4, 5];

// Collect into a new vector
let doubled: Vec<i32> = nums.iter()
    .map(|x| x * 2)
    .collect();

// Sum all values
let total: i32 = nums.iter().sum();

// Count items
let count = nums.iter().count();

🎮 Putting It All Together

Let’s build a complete example:

Problem: Find all words longer than 3 letters, and make them UPPERCASE.

let words = vec!["hi", "hello", "rust", "is", "fun"];

let result: Vec<String> = words.iter()
    .filter(|word| word.len() > 3)
    .map(|word| word.to_uppercase())
    .collect();

println!("{:?}", result);
// ["HELLO", "RUST"]

Breaking It Down

  1. Start: ["hi", "hello", "rust", "is", "fun"]
  2. Filter (len > 3): ["hello", "rust"]
  3. Map (uppercase): ["HELLO", "RUST"]

🧠 Key Takeaways

Concept Remember This
Iterator trait The promise to give items one at a time
Lazy evaluation Nothing happens until you consume
Iterator adaptors Machines that transform the assembly line
map Transform every item (same count)
filter Keep only items that pass the test

🚀 You Did It!

You now understand Rust iterators like a pro! Remember:

Iterators are like a lazy chocolate factory—the machines only start when someone is hungry!

Go forth and chain those adaptors! 🎉

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.