Control flow
Conditions, loops, defer, and the statements that leave a block.
Conditions are parenthesized.
function sign(x: i32): i32 {
if (x > 0) {
return 1;
} else {
return 0;
}
}
Loops
while takes a condition. The C-style for takes an initializer, a condition and a step, and the
type annotation on the loop variable is optional.
function sum(): i32 {
let mut total: i32 = 0;
for (let i = 0; i < 10; i++) {
total += i;
}
return total;
}
for of walks a sequence. Binding the element as a reference avoids copying it.
function total(): i32 {
let arr: i32[3] = [1, 2, 3];
let mut sum: i32 = 0;
for (let x of arr) {
sum += x;
}
return sum;
}
function totalByReference(): i32 {
let arr: i32[3] = [1, 2, 3];
let mut sum: i32 = 0;
for (let x: &i32 of arr) {
sum += *x;
}
return sum;
}
Pattern-driven loops are covered in pattern matching.
defer
defer schedules an expression for the end of the scope. Several defers in one scope run in
reverse order — last registered, first to run — and all of them run before automatic drops.
import Io from "std::io";
function example(): void {
defer Io::println("third");
defer Io::println("second");
defer Io::println("first");
return;
}
That prints first, second, third.
Its real use is pairing an acquire with its release next to each other, so the release cannot be lost down a branch you forgot about:
import LibC from "std::libc";
function readFile(path: str): i32 {
let fd: i32 = LibC::File::open(path, LibC::File::O_RDONLY);
if (fd == -1) {
return -1;
}
defer LibC::File::close(fd);
return 0;
}
Defers fire at every exit: return, break, continue, and falling off the end of the block. Two
restrictions: the deferred expression must be void-typed, and the try operator ! is not allowed
inside one.
Leaving a block
function example(): i32 {
let mut i: i32 = 0;
while (i < 10) {
if (i == 5) {
break;
}
if (i == 2) {
i += 1;
continue;
}
i += 1;
}
return i;
}