138

Editor's note: This question was asked before Rust 1.0 was released and the .. "range" operator was introduced. The question's code no longer represents the current style, but some answers below uses code that will work in Rust 1.0 and onwards.

I was playing on the Rust by Example website and wanted to print out fizzbuzz in reverse. Here is what I tried:

fn main() {
    // `n` will take the values: 1, 2, ..., 100 in each iteration
    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);
        }
    }
}

There were no compilation errors, but it did not print out anything. How do I iterate from 100 to 1?

Herohtar
  • 5,347
  • 4
  • 31
  • 41
Tybalt
  • 1,571
  • 2
  • 9
  • 8

2 Answers2

301

A forward loop is like this:

for x in 0..100 {
    println!("{}", x);
}

And a reverse loop is done by calling Iterator::rev to reverse the order:

for x in (0..100).rev() {
    println!("{}", x);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Luxspes
  • 6,268
  • 2
  • 28
  • 31
  • 5
    in rust, 0..10 means from 0 to 9, 10 is not included. so does (0..10).rev() mean "10 to 1" or "9 to 0"? – Bill Yan Oct 25 '20 at 01:00
  • 6
    The parentheses help clear this up. The range will be evaluated first (0 to 9), which is then reversed (9 to 0). – jtst Oct 26 '20 at 18:11
69

Editor's note: This question refers to parts of Rust that predate Rust 1.0. Look at other answers for up to date code.

Your code doesn't work because a uint of value -1 is equal the maximum value of uint. The range_step iterator stops immediately upon detecting overflow. Using an int fixes this.

std::iter::range_step(100i, 0, -1)

You can also reverse an iterator with rev().

for n in range(0u, 100).rev() { ... }

Though note that this will be from 99->0, rather than 100->1.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
A.B.
  • 15,364
  • 3
  • 61
  • 64
  • 2
    So why doesn't the compiler complain about mixing the types? – Tybalt Aug 06 '14 at 21:47
  • 3
    @user1452670: You are not mixing types, `100u` is of type `uint`, `0` and `-1` are untyped integrals for which the compiler will *infer* a type. Here, `range_step` requires uniform arguments and receives `(uint, , )` so the compiler deduces they are all `uint`. If you had *specified* `0i`, or `-1i` then you would have had a mismatch. – Matthieu M. Aug 07 '14 at 07:06
  • 3
    @MatthieuM.: To be fair, the value of `-1` is known to the compiler and "inferring" its type to be `uint` could be made to produce a warning because it's not representable. The question is, how often this is an error or not. – sellibitze Aug 07 '14 at 15:14
  • @sellibitze: Certainly, a lint that would diagnose out-of-range assignments would be very welcome. – Matthieu M. Aug 07 '14 at 16:06
  • @sellibitze: There has been some [discussion about this on discuss.rust-lang.org](http://discuss.rust-lang.org/t/forbid-unsigned-integer/752). – Francis Gagné Dec 20 '14 at 01:17
  • 1
    The first one is obsolete and the second one is unstable. As things stand in 2022. %) – unegare Apr 04 '22 at 09:45
  • The "second one" (.rev()) is stable as of rust 1.0.0, according to documentation. I'm not sure where you're getting your information. – Richard Rast Jul 20 '23 at 17:59