Is there a better way to loop n times?

I need to repeat some code for special times, now I'm using following code:

for i in 0..n {
// some code
}

but it's a little annoying because i don't need i in my code and '0' means nothing to me.
is there a better way to do this? Someting like this

loop n {

}

// or
loop!(n, {})
3 Likes
for _ in 0..n { ... }

It's not that much more to type. If you really, desperately cannot stand typing four extra tokens, define a loop! macro.

11 Likes

is there any extra cost on boundary check using for?
Actually, what I mean is to repeat some code.

println!("some code");
println!("some code");
println!("some code");
// code above can fold as
loop 3 {
    println!("come code");
};

And what more important is it's more clear than for .
@DanielKeep Can I achive this by define loop! macro? as I know macro cannot capture n then repeat special times.

Isn't that what all loops are for? How is your loop different?

2 Likes

Every kind of finite loop has boundary checks.

There's no static unrolling. That's an optimisation LLVM will do if it feels it's necessary.

If n is an actual literal, you could do it with a proc macro (which I don't believe are stabilised in function form yet). If it's not a literal, you can't do it.

Just use a for loop unless you can demonstrate that it's actually an issue.

2 Likes

I have already know how many times i need to repeat, so I don't want boundary check.
And, I think for i in 0..n is not clear enough to express repeat n times. For example for i in 1..n+1 do the same thing but express different meaning.

yes, I understand. thanks a lot.

This doesn't make any sense to me... I still don't understand how your loop is somehow special and not like any other loop.

In C, if I wanted to printf "jump" 10 times, I would code:

size_t i;
for(i = 0; i < 10; i++)
{
   printf("Jump\n");
}

Here, I know that I want to print "Jump" 10 times.... I still have to specify 0-9 aka i < 10. That's just how programming works. Alternatively, I could specify:

size_t i;
while(i < 10)
{
   printf("Jump\n");
   i++;
}

Same thing, really. How else can I print jump 10 times aside from either writing a recursive solution or just copy/pasting printf("Jump\n"); into the source-code 10 times???

Sure, I could #define some macro which just pastes printf 10 times, but what's the point?

I'm not sure why this is an issue, and I'd just go with @DanielKeep's suggestions since it's pretty canonical and readable in rust. But just as a basic Rust exercise, here are a couple ways to not care about 0..n vs 1..n+1.

The loopn! (loop is a keyword) you asked for:

macro_rules! loopn {
  ($n:expr, $body:block) => {
      for _ in 0..$n {
          $body
      }
  }
}

Alternatively, a helper function supporting an iterator-based approach:

fn times(n: usize) -> impl Iterator {
    std::iter::repeat(()).take(n)
}

fn main() {
  for _ in times(5) {
      println!("Hello world!");
  }
}

Both can be seen in this playground.

5 Likes

I second the comment to check whether this is actually an issue, but you can unroll constant loops with crunchy.

https://crates.io/crates/crunchy

1 Like

I see 1..n+1, but no one has mentioned the inclusive-range operator as an alternative: 1..=n. Stable since Rust 1.26.

3 Likes

because it looks ugly. :joy_cat:

2 Likes

I strongly encourage getting used to ..'s half-openness -- it's far better in algorithms because it splits elegantly: if you divide low..high into low..mid and mid..high, you have all the same items with no overlap and no error-prone ±1 adjustments. This has been known since at least 1982: E.W. Dijkstra Archive: Why numbering should start at zero (EWD 831)

6 Likes

I was offering the inclusive range as an alternative to adding 1 on both sides. Personally, I wouldn't add 1 in the first place, and would stick to the exclusive range.