Local & Foreign Labels
Labels are introduced with a leading
, which is symmetric to how they are later referred to. Here is how to :
or continue
from a nested loop:
break
OUTER_LOOP
recipes.each: |recipe| {
recipe.ingredients.each: |ingredient|
if !(fridge.has(ingredient))
continue :OUTER_LOOP;
return recipe
}
:
We'll discuss iteration in the following chapter, in any case calls to .each
amount to a regular for (;;)
loop, and we're using them here for brevity.
Of note is that parent function labels are available to child functions:
OUTER_LOOP
recipes.each: |recipe| {
fn fail(reason: string) {
println("Cannot prepare " recipe.name ": " reason)
continue :OUTER_LOOP;
}
recipe.ingredients.each: |ingredient|
if !(fridge.has(ingredient))
fail("We don't have " ~ ingredient)
return recipe
}
:
Because
is now defined in the outer loop, the label has become redundant:
fn fail
recipe| {
fn fail(reason: string)
continue println("Cannot prepare " recipe.name ": " reason)
recipe.ingredients.each: |ingredient|
if !(fridge.has(ingredient))
fail("We don't have " ~ ingredient)
return recipe
}
recipes.each: |
Labelled Blocks and Block Expressions
You can
from labelled blocks, just like in JavaScript, Rust and Zig:
break
LABEL {
for (mut i = 0; i < 10; i++)
for (mut j = 0; j < 10; j++)
if (i == j)
break :LABEL;
println("This is never executed.")
}
:
Blocks are expressions, which allows you to wrap any statement in a block to place it in expression position:
let zero = {
println("Effect!")
0
}
The comma operator from C-style languages is not available, because blocks provide identical functionality.
Thus, the C-style expression a = (b, c)
is written as a = { b; c }
.
You can
with a value from labelled block expressions:
break
let zero = {
:LABEL {
for (mut i = 0; i < 10; i++)
for (mut j = 0; j < 10; j++)
if (i == j)
break :LABEL i;
-1
}
}
assert(zero == 0)