Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Scope and declarations

var creates a name in the current lexical scope. A name declared in a block is visible inside nested blocks, but not after the block ends. Assignment updates the nearest existing name; use var when a new local binding is intended.

var message = "outside"
if true {
    var detail = "inside"
    message = "changed"
    print(detail)
}
print(message) # changed
# detail is not visible here

Functions capture the surrounding lexical scope. Each for iteration has its own loop binding, so functions created in a loop retain that iteration's value.

var readers = []
for value in [1, 2, 3] {
    readers.push(func() { return value })
}
print(readers[0](), readers[1](), readers[2]()) # 1 2 3

Declarations at module scope

import, type, and export are allowed only at module scope. Module-level import, func, and type names are hoisted: they are visible throughout the module regardless of where the definition appears, so functions may call functions defined later — including mutually recursive pairs.

func is_even(n) {
    if n == 0 { return true }
    return is_odd(n - 1)
}

func is_odd(n) {
    if n == 0 { return false }
    return is_even(n - 1)
}

print(is_even(10))

Other names must be declared before use: local var declarations (and nested function definitions) are not available before their declaration. Keep declarations near the beginning of the block when that makes a function easier to read.

Shadowing built-in functions

A user declaration may reuse a built-in function's name. The innermost binding wins, and the built-in becomes visible again once the shadowing scope ends:

func min(a, b) {
    return "user min"
}
print(min(1, 2)) # user min

if true {
    var max = 100
    print(max)   # 100
}
print(max(1, 2)) # 2 — the built-in is back in scope

Go keywords such as map or range cannot be used as names at all; see Syntax and call rules.