Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would you write the equivalent of this C++ loop in Rust

Rust's for loops are a bit different than those in C-style languages. I am trying to figure out if I can achieve the same result below in a similar fashion in Rust. Note the condition where the i^2 < n.

for (int i = 2; i * i < n; i++)
{
    // code goes here ...
}
like image 366
Midas Avatar asked Sep 02 '18 18:09

Midas


People also ask

How to write loops in Rust?

Rust provides a loop keyword to indicate an infinite loop. The break statement can be used to exit a loop at anytime, whereas the continue statement can be used to skip the rest of the iteration and start a new one.

Does rust have for loop?

Rust supports four loop expressions: A loop expression denotes an infinite loop. A while expression loops until a predicate is false. A while let expression tests a pattern.

How do you break a loop in Rust?

The break control statement allows us to stop the execution of a loop, break out of its iteration cycle and continue on to any code after it. To use the break control statement, we simply write the break keyword where we want to break out of the loop.


2 Answers

You can always do a literal translation to a while loop.

let mut i = 2;
while i * i < n {
    // code goes here
    i += 1;
}

You can also always write a for loop over an infinite range and break out on an arbitrary condition:

for i in 2.. {
    if i * i >= n { break }
    // code goes here
}

For this specific problem, you could also use take_while, but I don't know if that is actually more readable than breaking out of the for loop. It would make more sense as part of a longer chain of "combinators".

for i in (2..).take_while(|i| i * i < n) {
    // code goes here
}
like image 94
zwol Avatar answered Oct 14 '22 07:10

zwol


The take_while suggestion from zwol's answer is the most idiomatic, and therefore usually the best choice. All of the information about the loop is kept together in a single expression instead of getting mixed into the body of the loop.

However, the fastest implementation is to precompute the square root of n (actually a weird sort of rounded-down square root). This lets you avoid doing a comparison every iteration, since you know this is always the final value of i.

let m = (n as f64 - 0.5).sqrt() as _;
for i in 2 ..= m {
    // code goes here
}

As a side note, I tried to benchmark these different loops. The take_while was the slowest. The version I just suggested always reported 0 ns/iter, and I'm not sure if that's just due to some code being optimised to the point of not running at all, or if it really is too fast to measure. For most uses, the difference shouldn't be important though.

like image 32
Peter Hall Avatar answered Oct 14 '22 06:10

Peter Hall