Control flow#
Control flow is how the operator’s program decides what runs
next. Lua keeps the surface small: if / elseif / else
for branching, while / repeat / for for iteration,
break / return / goto for jumps. There is no
switch and no exception flow; protected calls (pcall)
handle errors.
This page is the day-to-day reference for the control-flow
constructs. For the values they branch on, see Types.
For error / pcall, see Errors.
Conditional#
if / elseif / else evaluates branches top-to-bottom
and takes the first whose condition is truthy. Only false
and nil are falsy; everything else is truthy.
flowchart TD
A([start]) --> B{x > 0?}
B -->|true| C[positive]
B -->|false| D{x == 0?}
D -->|true| E[zero]
D -->|false| F[negative]
C --> Z([end])
E --> Z
F --> Z
if x > 0 then
positive()
elseif x == 0 then
zero()
else
negative()
end
Lua has no ternary operator, but and / or short-circuit
to the same effect when the consequent is itself truthy.
local label = (n % 2 == 0) and "even" or "odd"
Loops#
Three loop forms, picked by what the operator is iterating.
While loop#
flowchart TD
A([start]) --> B{cond?}
B -->|true| C[body]
C --> B
B -->|false| D([end])
Tests the condition first; skips the body when already false.
local i = 1
while i <= 10 do
print(i)
i = i + 1
end
Repeat-until#
flowchart TD
A([start]) --> B[body]
B --> C{cond?}
C -->|false| B
C -->|true| D([end])
Post-test loop. The body runs once before the condition is
checked; the loop exits when the condition turns true. Locals
declared in the body are in scope inside the until
expression, which is rare in other languages and useful for
seeded loops.
repeat
local line = io.read()
process(line)
until line == "quit"
Numeric for#
Runs the control variable from a start to a stop value in optional steps. The bounds are evaluated once at entry.
Default step of 1.
for i = 1, 10 do print(i) end
Explicit step.
for i = 1, 10, 2 do print(i) end
Negative step for a countdown.
for i = 10, 1, -1 do print(i) end
Generic for#
Drives an iterator function. ipairs walks a sequence
(integer keys 1..n); pairs walks every key in any order.
Custom iterators are functions that return the next value (or
nil to stop).
ipairs walks integer keys 1..n in order.
for i, v in ipairs({"a", "b", "c"}) do
print(i, v)
end
pairs walks every key in any order.
for k, v in pairs({name = "rk", age = 30}) do
print(k, v)
end
A custom iterator (here string.gmatch) is just a function
that returns the next value or nil to stop.
for word in string.gmatch("one two three", "%a+") do
print(word)
end
Jumps#
break, return, and goto interrupt the natural
top-to-bottom flow.
Keyword |
Effect |
|---|---|
|
Exit the innermost |
|
Exit the current function (optionally with values). Must
be the last statement in a block; use |
|
Jump to a named |
for _, line in ipairs(lines) do
if line:sub(1, 1) == "#" then
goto continue -- skip comment lines
end
process(line)
::continue::
end
Lua has no continue keyword. The goto continue pattern
above is the standard workaround.