While and Loop
Move offers two constructs for looping: while
and loop
.
while
loops
The while
construct repeats the body (an expression of type unit) until the condition (an expression of type bool
) evaluates to false
.
Here is an example of simple while
loop that computes the sum of the numbers from 1
to n
:
fun sum(n: u64): u64 {
let sum = 0;
let i = 1;
while (i <= n) {
sum = sum + i;
i = i + 1
};
sum
}
Infinite loops are allowed:
fun foo() {
while (true) { }
}
break
The break
expression can be used to exit a loop before the condition evaluates to false
. For example, this loop uses break
to find the smallest factor of n
that's greater than 1:
fun upper_bound_sqrt(n: u64): u64 {
// assuming the input is not 0 or 1
let i = 2;
while (i <= n) {
if (n % i == 0) break;
i = i + 1
};
i
}
The break
expression cannot be used outside of a loop.
continue
The continue
expression skips the rest of the loop and continuess to the next iteration. This loop uses continue
to compute the sum of 1, 2, ..., n
, except when the number is divisible by 10:
fun sum_intermediate(n: u64): u64 {
let sum = 0;
let i = 1;
while (i <= n) {
if (i % 10 == 0) continue;
sum = sum + i;
i = i + 1
};
sum
}
The continue
expression cannot be used outside of a loop.
The type of break
and continue
break
and continue
, much like return
and abort
, can have any type. The following examples illustrate where this flexible typing can be helpful:
fun pop_smallest_while_not_equal(
v1: vector<u64>,
v2: vector<u64>,
): vector<u64> {
let result = Vector::empty();
while (!Vector::is_empty(&v1) && !Vector::is_empty(&v2)) {
let u1 = *Vector::borrow(&v1, Vector::length(&v1) - 1);
let u2 = *Vector::borrow(&v1, Vector::length(&v1) - 1);
let popped =
if (u1 < u2) Vector::pop_back(&mut v1)
else if (u2 < u1) Vector::pop_back(&mut v2)
else break; // Here, `break` has type `u64`
Vector::push_back(&mut result, popped);
};
result
}
fun pick(
indexes: vector<u64>,
v1: &vector<address>,
v2: &vector<address>
): vector<address> {
let len1 = Vector::length(v1);
let len2 = Vector::length(v2);
let result = Vector::empty();
while (!Vector::is_empty(&indexes)) {
let index = Vector::pop_back(&mut indexes);
let chosen_vector =
if (index < len1) v1
else if (index < len2) v2
else continue; // Here, `continue` has type `&vector<address>`
Vector::push_back(&mut result, *Vector::borrow(chosen_vector, index))
};
result
}
The loop
expression
The loop
expression repeats the loop body (an expression with type ()
) until it hits a break
Without a break
, the loop will continue forever
fun foo() {
let i = 0;
loop { i = i + 1 }
}
Here is an example that uses loop
to write the sum
function:
fun sum(n: u64): u64 {
let sum = 0;
let i = 0;
loop {
i = i + 1;
if (i > n) break;
sum = sum + i
};
sum
}
As you might expect, continue
can also be used inside a loop
. Here is sum_intermediate
from above rewritten using loop
instead of while
fun sum_intermediate(n: u64): u64 {
let sum = 0;
let i = 0;
loop {
if (i % 10 == 0) continue;
i = i + 1;
if (i > n) break;
sum = sum + i
};
sum
}
The type of while
and loop
Move loops are typed expressions. A while
expression always has type ()
.
let () = while (i < 10) { i = i + 1 };
If a loop
contains a break
, the expression has type unit ()
(loop { if (i < 10) i = i + 1 else break }: ());
let () = loop { if (i < 10) i = i + 1 else break };
If loop
does not have a break
, loop
can have any type much like return
, abort
, break
, and continue
.
(loop (): u64);
(loop (): address);
(loop (): &vector<vector<u8>>);