Reputation: 573
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 ...
}
Upvotes: 11
Views: 4782
Reputation: 140445
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
}
Upvotes: 20
Reputation: 1287
Update: I have learned more Rust since I wrote this answer. This structure is still useful for some rare situations (like when the logic inside the loop needs to conditionally mutate the counter variable), but usually you'll want to use a Range Expression like zwol said.
I like this form, since it keeps the increment at the top of the loop instead of the bottom:
let mut i = 2 - 1; // You need to subtract 1 from the initial value.
loop {
i+=1; if i*i >= n { break }
// code goes here...
}
Upvotes: 2
Reputation: 58695
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.
Upvotes: 5