Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to break out of a do-while style loop in Rust?

Tags:

rust

Rust allows a kind of do-while loop eg:

So the C style:

do {
    something();
} while (test());

Can be written in Rust as:

while {
    something();
    test()
}{}

However there is a problem using break in this case:

So this C style:

do {
    if (something()) {
        break;
    }
} while (test());

Can't be written in Rust as:

while {
    if (something()) {
        break;
    }
    test()
}{}

Fails to compile with cannot break outside of a loop.

Is there a way to break out of this form of while loop?


Note 1) the reason to use:
do {...} while test() flow control instead of
while test() {...} is in this case test() will be false when entering the loop initially.

Note 2) When using while {...} flow control: calling continue in the body of the code will skip the break check at the end.

See related question: How to wrap a do-while style loop in a macro, maintaining 'continue' flow control?

like image 717
ideasman42 Avatar asked Mar 10 '23 18:03

ideasman42


2 Answers

You are overthinking this.

Let's build a truth table:

+-------------+--------+--------+
| something() | test() | Result |
+-------------+--------+--------+
|    true     |  true  |  stop  |
+-------------+--------+--------+
|    true     |  false |  stop  |
+-------------+--------+--------+
|    false    |  true  |  go on |
+-------------+--------+--------+
|    false    |  false |  stop  |
+-------------+--------+--------+

Thus, this can be written as:

while !something() && test {}

There is no need for a break.

like image 34
Matthieu M. Avatar answered Mar 20 '23 03:03

Matthieu M.


As mentioned in the comments, it is important to understand how this pattern works. It is not a special form of while, it simply abuses the loop test to do things normally done in the body. Since break and continue don't belong in the loop test (unless the loop is part of another loop, in which case they will compile, but break/continue the outer loop), Rust rejects them.

A straightforward way to emulate break with the above pattern is by moving the test code to a closure from which one can exit with return:

while (|| {
    if something() {
        return false // break
    }
    test()
})() {}

continue can be emulated the same way, simply by returning true from the closure.

It would probably possible to make the intention clearer if this were expressed as a macro.

like image 89
user4815162342 Avatar answered Mar 20 '23 03:03

user4815162342