Question
I want to print FizzBuzz in reverse order in Rust, counting from 100 down to 1.
I tried this code:
fn main() {
for n in std::iter::range_step(100u, 0, -1) {
if n % 15 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
} else {
println!("{}", n);
}
}
}
The code compiles, but it does not print anything. How can I correctly iterate from 100 down to 1 in Rust?
Short Answer
By the end of this page, you will understand how reverse iteration works in Rust, why some descending loop attempts produce no output, and how to correctly loop from a larger number down to a smaller one using ranges and .rev(). You will also see practical examples, common mistakes, and a small reverse-counting mini-project.
Concept
In Rust, a for loop works by iterating over an iterator. That means the important question is not just “what numbers do I want,” but also “what iterator produces them?”
For counting upward, Rust ranges are straightforward:
for n in 1..=5 {
println!("{}", n);
}
This prints 1 through 5.
For counting downward, Rust does not usually use a negative step directly in a range expression. Instead, the common Rust style is:
- Create a normal forward range.
- Reverse it with
.rev().
Example:
for n in (1..=5).rev() {
println!("{}", n);
}
This prints 5 down to 1.
This matters because Rust's iterator system is designed to be explicit, safe, and composable. Rather than special loop syntax for every situation, Rust encourages you to build the iterator you want. Reversing an iterator is one of the most common tools for this.
In your original code, the issue is that the iterator setup did not actually produce values in the way you expected. In modern Rust, the clearest and most idiomatic solution is to use a range with .rev().
Mental Model
Think of a Rust range like a list of pages in a book.
1..=5means: pages 1, 2, 3, 4, 5.rev()means: read those pages from the back to the front
So instead of asking Rust to “walk backward with a negative step,” you usually tell it:
- “Make the normal sequence first”
- “Now reverse it”
That is much like stacking numbered cards from 1 to 100, then flipping the stack over and reading from the top.
Syntax and Examples
The most common way to write a reverse loop in Rust is:
for n in (start..=end).rev() {
// use n
}
Example: count from 5 down to 1
fn main() {
for n in (1..=5).rev() {
println!("{}", n);
}
}
Output:
5
4
3
2
1
Example: reverse FizzBuzz from 100 to 1
fn main() {
for n in (1..=100).rev() {
if n % 15 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
} else {
println!("{}", n);
}
}
}
Exclusive vs inclusive ranges
Rust has two very common range forms:
1..5 // 1, 2, 3, 4
1..=5 // 1, 2, 3, 4, 5
If you want to include 100 and 1, use an inclusive range and reverse it:
for n in (1..=100).rev() {
println!("{}", n);
}
Alternative with while
You can also count down manually:
fn main() {
let mut n = 100;
while n >= 1 {
println!("{}", n);
n -= 1;
}
}
This works, but for simple iteration, for with a range is usually cleaner and more idiomatic in Rust.
Step by Step Execution
Consider this code:
fn main() {
for n in (1..=5).rev() {
println!("{}", n);
}
}
Here is what happens step by step:
-
Rust creates the range
1..=5.- This represents the values
1, 2, 3, 4, 5.
- This represents the values
-
.rev()is called on that range.- The iterator is reversed.
- Now it will yield
5, 4, 3, 2, 1.
-
The
forloop starts.- First iteration:
n = 5 println!prints5
- First iteration:
-
Second iteration:
n = 4println!prints4
-
The loop continues:
n = 3n = 2n = 1
-
After
1, the iterator has no more values.- The loop ends.
Trace table
| Iteration | Value of n | Printed |
|---|---|---|
| 1 | 5 | 5 |
| 2 | 4 | 4 |
| 3 | 3 | 3 |
| 4 | 2 | 2 |
| 5 | 1 | 1 |
Now apply the same idea to 1..=100, and you get a clean reverse loop from 100 down to 1.
Real World Use Cases
Reverse iteration appears in many real programs, not just counting examples.
Common practical uses
-
Displaying recent items first
- Show newest notifications before older ones.
-
Countdowns
- Timers, launch countdowns, game start sequences.
-
Processing collections from the end
- Some algorithms inspect the last items first.
-
Undo history
- Traverse recent actions in reverse order.
-
Log analysis
- Read recent events before older records.
Example: countdown
fn main() {
for seconds in (1..=10).rev() {
println!("{}...", seconds);
}
println!("Go!");
}
Example: iterating a vector in reverse
fn main() {
let messages = vec!["old", "middle", "new"];
for message in messages.iter().rev() {
println!("{}", message);
}
}
This prints the newest item first if the vector is stored oldest-to-newest.
Real Codebase Usage
In real Rust codebases, developers often use reverse iteration with iterator adapters rather than manual index manipulation.
Common patterns
Reverse a range
for i in (0..10).rev() {
println!("{}", i);
}
Useful for countdowns or reverse traversal.
Reverse a collection iterator
let items = vec![1, 2, 3, 4];
for item in items.iter().rev() {
println!("{}", item);
}
This avoids indexing and is safer.
Combine with filters or mapping
let nums = vec![1, 2, 3, 4, 5, 6];
for n in nums.iter().rev().filter(|n| **n % 2 == 0) {
println!("{}", n);
}
This is common in data processing pipelines.
Guarding boundaries clearly
When reverse loops involve endpoints, developers often choose inclusive ranges so the intent is obvious:
for id in (1..=max_id).rev() {
// process from latest to earliest
}
This is easier to read than custom stepping logic.
Why this style is preferred
- It is idiomatic Rust.
- It works well with the iterator ecosystem.
- It reduces off-by-one mistakes.
- It avoids unsafe or confusing manual control flow.
Common Mistakes
1. Forgetting that .. excludes the end value
Broken example:
for n in (1..100).rev() {
println!("{}", n);
}
This prints 99 down to 1, not 100 down to 1.
Correct version:
for n in (1..=100).rev() {
println!("{}", n);
}
2. Expecting a negative step in modern range syntax
Beginners sometimes expect something like this to work:
// Not valid modern Rust range syntax for descending loops
for n in 100..1 {
println!("{}", n);
}
A forward range where the start is larger than the end yields no values.
Use:
for n in (1..=100).rev() {
println!("{}", n);
}
3. Missing parentheses before .rev()
Broken example:
for n in 1..=100.rev() {
println!("{}", n);
}
The method must be called on the whole range, not just on 100.
Correct:
for n in (1..=100).rev() {
println!("{}", n);
}
4. Using while and forgetting to update the counter
Broken example:
let mut n = 100;
while n >= 1 {
println!("{}", n);
}
This causes an infinite loop because n never changes.
Correct:
let mut n = 100;
while n >= 1 {
println!("{}", n);
n -= 1;
}
5. Off-by-one errors at the lower bound
Broken example:
let mut n = 100;
while n > 1 {
println!("{}", n);
n -= 1;
}
This never prints 1.
Correct:
let mut n = 100;
while n >= 1 {
println!("{}", n);
n -= 1;
}
Comparisons
| Approach | Example | Best for | Notes |
|---|---|---|---|
for with reversed range | for n in (1..=100).rev() | Simple reverse counting | Most idiomatic for numeric countdowns |
while loop | while n >= 1 | Custom loop control | More manual, easier to make mistakes |
| Reverse collection iterator | items.iter().rev() | Traversing arrays, vectors, slices | Preferred over manual indexing |
| Forward range | for n in 1..=100 | Normal ascending iteration | Not for descending order unless combined with .rev() |
for vs while
| Feature | for | while |
|---|---|---|
| Readability | High for simple iteration | Good for custom conditions |
| Safety | Fewer manual mistakes | More room for infinite loops |
| Idiomatic Rust | Very common | Used when more control is needed |
| Best use case | Iterating known sequences | Complex stopping logic |
Inclusive vs exclusive ranges
| Syntax | Includes end? | Example values |
|---|---|---|
1..5 | No | 1, 2, 3, 4 |
1..=5 | Yes | 1, 2, 3, 4, 5 |
For looping from 100 down to 1, 1..=100 is usually the correct starting range before reversing.
Cheat Sheet
// Count up
for n in 1..=5 {
println!("{}", n);
}
// Count down
for n in (1..=5).rev() {
println!("{}", n);
}
// Exclusive upper bound
for n in (1..5).rev() {
println!("{}", n); // prints 4, 3, 2, 1
}
// Manual countdown
let mut n = 5;
while n >= 1 {
println!("{}", n);
n -= 1;
}
Quick rules
- Use
..for an exclusive end. - Use
..=for an inclusive end. - Use
.rev()to reverse a range or iterator. - Put parentheses around the range before calling
.rev(). - Prefer
foroverwhilewhen iterating a known sequence.
Common pattern
for n in (start..=end).rev() {
// descending loop
}
Example for this topic
for n in (1..=100).rev() {
println!("{}", n);
}
FAQ
How do I loop backwards in Rust?
Use a normal range and reverse it with .rev():
for n in (1..=10).rev() {
println!("{}", n);
}
Why does 100..1 not work the way I expect?
Rust ranges normally move forward. If the start is greater than the end, the range produces no values.
What is the difference between .. and ..= in Rust?
..excludes the end value..=includes the end value
So 1..100 stops at 99, while 1..=100 includes 100.
Is .rev() only for ranges?
No. It also works on many iterators, such as vectors, slices, and other iterable collections.
Should I use for or while for reverse loops?
Use for when you are iterating over a known range. Use while when you need more manual control.
How do I print FizzBuzz from 100 down to 1 in Rust?
Use:
for n in (1..=100).rev() {
// fizzbuzz logic
}
Do I need parentheses around the range before .rev()?
Yes, usually:
for n in (1..=100).rev() {
println!("{}", n);
}
Mini Project
Description
Build a small Rust program that prints a reverse countdown with custom messages. This project helps you practice descending for loops, inclusive ranges, and conditional logic together. It is similar to reverse FizzBuzz but simpler to modify and test.
Goal
Create a Rust program that counts from 10 down to 1 and prints special labels for certain numbers.
Requirements
- Count from 10 down to 1 using a
forloop. - Use an inclusive range and reverse it.
- Print
evenfor even numbers. - Print
multiple of 3for numbers divisible by 3. - Print the number itself for all other values.
Keep learning
Related questions
Absolute Values in Rust: Using the abs() Method
Learn how to calculate absolute values in modern Rust with abs(), handle signed integer overflow, and choose safer alternatives.
Accepting Iterators in Rust Functions with impl Iterator
Learn how to write Rust functions that accept HashMap iterators using generic bounds or impl Iterator, avoiding trait object and lifetime errors.
Access Enum Variant Values in Rust with Pattern Matching
Learn how to extract and print values stored in Rust enum variants using match and if let pattern matching, with practical examples.