Control flow
Blocks
Section titled “Blocks”A block is a sequence of expressions inside braces { ... }. The last expression is the block’s value. Bindings inside are not visible outside.
let value = { let a = 10 let b = 20 a + bvalue is 30}if else
Section titled “if else”if count > 0 { fmt.Println("has items")}
if count > 10 { fmt.Println("large")} else { fmt.Println("small")}When both branches are present, if else returns a value. Both branches must produce the same type.
let label = if count > 10 { "large" } else { "small" }
let clamped = if n > max { max} else if n < min { min} else { n}An if without else has type ().
if let
Section titled “if let”Runs the body when a pattern matches. Most commonly used with Option.
if let Some(x) = opt { fmt.Println(x)}With else, it works as an expression:
let value = if let Some(x) = opt { x} else { 0}Iterates over a collection or range, for its side effects.
for item in items { fmt.Println(item)}
for i in 0..5 { fmt.Println(i)prints 0, 1, 2, 3, 4}Supported iterables:
| Iterable | Element type |
|---|---|
Slice<T> | T |
Array<T, N> | T |
Map<K, V> | (K, V) |
Range<T>, RangeInclusive<T>, RangeFrom<T> | T |
Channel<T>, Receiver<T> | T |
EnumeratedSlice<T> | (int, T) |
iter.Seq<T> | T |
iter.Seq2<K, V> | (K, V) |
See Functions for writing an iterator
To iterate over a string, pick a unit:
for r in s.runes() { fmt.Println(r)}
for b in s.bytes() { fmt.Println(b)}Maps require destructuring into key and value:
for (name, age) in ages { fmt.Println(name, age)}Use enumerate() for indexed iteration over a slice:
for (i, item) in items.enumerate() { fmt.Println(i, item)}Open-ended ranges start.. loop until a break:
for i in 0.. { if i >= 10 { break }}Repeats while a condition is true, for its side effects.
let mut total = 0while total < 10 { total += 3}while let
Section titled “while let”Repeats as many times as a pattern matches.
let mut i = 0while let Some(item) = items.get(i) { fmt.Println(item) i += 1}An infinite loop. Exit with break.
let mut n = 0loop { n += 1 if n == 10 { break }}A loop has no exit other than break, which can carry a value, so a loop evaluates to the value carried by break.
let mut n = 0let result = loop { n += 7 if n > 20 { break nresult is 21 }}A bare break gives the loop type ().
break and continue
Section titled “break and continue”break exits a loop. continue skips to the next iteration of the loop.
for i in 0..100 { if i % 2 == 0 { continue } if i > 50 { break } fmt.Println(i)}There are no labeled breaks. break and continue always apply to the innermost loop.
return
Section titled “return”Returns early from the current function. A bare return returns ().
fn find(items: Slice<int>, target: int) -> Option<int> { for i in 0..items.length() { if items[i] == target { return Some(i)early return } } None}Schedules an expression to run when the enclosing function returns, no matter how it returns.
fn file_size(path: string) -> Result<int64, error> { let file = os.Open(path)? defer file.Close()runs on function exit, whether file.Stat() succeeds or fails let info = file.Stat()? Ok(info.Size())}When a function has several defer calls, the last one scheduled runs first.
defer fmt.Println("first")defer fmt.Println("second")runs before firstA defer block groups cleanup steps that belong together. Inside one block the steps run in the order written, top to bottom.
defer { conn.flush()runs first conn.close()runs second}