Loops

Rux has four loops. Each runs a block repeatedly; they differ in when, or whether, they test a condition.

LoopTestsThe body runs
while c { … }before each passzero or more times
do { … } while c;after each passat least once
loop { … }neveruntil a break or return
for x in s { … }for a next element of sonce per element
while-loop = [label ":"] "while" condition block
do-while   = [label ":"] "do" block "while" condition ";"
loop       = [label ":"] "loop" block
for-loop   = [label ":"] "for" Name "in" expression block

Any loop may carry a label, so that a break or continue inside a nested loop can name it — see break and continue. Conditions follow the rules in Statements: a bool, no parentheses needed, a structure literal wrapped in parentheses.

while

while tests its condition before every pass, including the first, so the body may never run:

var i = 0;
while i < 3 {
    PrintLine("{}", i);
    i++;
}

do while

do … while runs the body first and tests afterwards, so the body always runs at least once. The statement ends with ;:

var tries = 5;
do {
    tries--;
} while tries > 10;

The condition is false from the start, but tries is still decremented once, to 4. A continue in the body goes straight to the test.

loop

loop repeats until something leaves it — a break, a return, a fail, or a panic. It says "until I stop it" more directly than while true:

var n = 0;
loop {
    n += 1;
    if n == 4 {
        break;
    }
}

for

for runs its body once for each element of a sequence, binding the element to the loop variable:

let values = [10, 20, 30];
for v in values {
    PrintLine("{}", v);
}

The subject is evaluated once, before the first pass. What for can iterate:

SubjectElements
a fixed-size array T[N]each element, in order
a slice T[..]each element, in order
a string literal or other char8[..]each char8 code unit — a byte of UTF-8, not a character
a range a..b, a..=b, a...beach integer from a, up to b exclusive or inclusive
an open range a..each integer from a, until the loop is left
a type with an iteratoreach value its iterator's Next returns
for k in 0..3 {
    Print("{} ", k);
}
for k in 0..=3 {
    Print("{} ", k);
}

This prints 0 1 2 0 1 2 3. A range whose start is past its end runs zero times. When both ends are constants, the compiler catches it instead: for k in 5..2 is error: range start cannot be greater than its end. See Ranges.

Any other type is iterated through the iterator convention: a container declares a parameterless Iterate returning an iterator, and the iterator declares func Next(self: &var Iterator) -> Item?. Each pass calls Next once; a present result is the element, and none ends the loop. See Iteration.

for left in countdown {
    Print("{} ", left);
}

A type with neither is refused:

error: cannot iterate over 'int'
  help: iterate an array, a slice, a range, or a type declaring 'Next' or 'Iterate'

The loop variable

The loop variable is a single name, fresh on every pass and immutable: i = 10; inside for i in 0..3 is error: cannot modify immutable variable 'i'. It cannot be declared var, and it cannot be a pattern — for (a, b) in pairs does not parse. Bind a mutable copy or take an element apart inside the body:

for pair in pairs {
    let (a, b) = pair;
    PrintLine("{} {}", a, b);
}

Moving inside a loop

A loop body runs again from where its last pass ended, so a value one pass moves out is not there for the next. Moving an outer variable inside a loop is an error unless the same pass gives it a new value before the loop repeats, or leaves the loop after the move:

for i in 0..3 {
    Consume(<- buffer);
}
error: value 'buffer' may have been moved on some control-flow paths

The loop variable, and bindings declared inside the body, are new on every pass and may be moved freely. See Copy and move.

See also