Statements control execution (spec: Statements). Declarations are also statements, and a block may hold both in any order.
Statement = Declaration | LabeledStmt | SimpleStmt |
GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
DeferStmt .
SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
Terminating statements
A function with result parameters must end in a terminating statement (since Go 1.1). The rule is purely syntactic (spec: Terminating statements). A statement is terminating if it is:
- a
returnorgoto; - a call to the built-in
panic; - a block whose statement list ends in a terminating statement;
- an
ifwith anelse, where both branches are terminating; - a
forwith no condition, no range clause, and nobreakreferring to it; - a
switchwith adefaultcase and nobreakreferring to it, whose every case ends in a terminating statement or a possibly labelledfallthrough; - a
selectwith nobreakreferring to it, whose every case ends in a terminating statement; - a labelled statement labelling a terminating statement.
A statement list ends in a terminating statement if it is not empty and its final non-empty statement is terminating.
Simple statements
Empty statements
The empty statement does nothing: EmptyStmt = .
Expression statements
Function and method calls and receive operations can stand as statements. These built-in
functions cannot: append cap complex imag len make new real unsafe.Add
unsafe.Alignof unsafe.Offsetof unsafe.Sizeof unsafe.Slice unsafe.SliceData unsafe.String
unsafe.StringData. The gc compiler also rejects min and
max here.
Send statements
SendStmt = Channel "<-" Expression .
Channel = Expression .
Sends a value on a channel: ch <- 3. Both operands are evaluated first.
Sending blocks until the send can proceed. See
Concurrency.
IncDec statements
IncDecStmt = Expression ( "++" | "--" ) .
x++ is x += 1 and x-- is x -= 1. The
operand must be addressable or a map index expression. These are statements, not
expressions, so they cannot be used inside an expression.
Assignment statements
Assignment = ExpressionList assign_op ExpressionList .
assign_op = [ add_op | mul_op ] "=" .
Each left-hand operand must be addressable, a map index expression or, for =
only, the blank identifier. x op= y means x = x op (y) but
evaluates x only once. A tuple assignment assigns the values of a
multi-valued operation, or matching lists of single-valued expressions, to a list of
variables.
Assignment has two phases. First the operands of index expressions and pointer indirections on the left, and the expressions on the right, are evaluated in the usual order. Second, the assignments are done left to right (spec: Assignment statements).
a, b = b, a // exchange a and b
x := []int{1, 2, 3}
i := 0
i, x[i] = 1, 2 // set i = 1, x[0] = 2
i = 0
x[i], i = 2, 1 // set x[0] = 2, i = 1
x[0], x[0] = 1, 2 // set x[0] = 1, then x[0] = 2
x[1], x[3] = 4, 5 // set x[1] = 4, then panic setting x[3] = 5
_ = x // evaluate x but ignore it
x, _ = f() // evaluate f() but ignore second result value
Each value must be assignable to its target. An untyped constant assigned to an interface variable or the blank identifier is first converted to its default type. Assignment copies the value only; a slice or map value still shares its underlying data.
Labelled statements
LabeledStmt = Label ":" Statement .
Label = identifier .
A labelled statement may be the target of a goto, break or
continue. Labels must be used, are scoped to the function body, and do not
conflict with other identifiers (see
Label scopes).
If statements
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
if x > max {
x = max
}
if x := f(); x < y {
return x
} else if x > z {
return z
} else {
return y
}
The condition must be a boolean and needs no parentheses. Braces are required. There is no conditional expression or ternary operator in Go.
Switch statements
A switch compares an expression or a type against cases and executes one
branch. There are expression switches and type switches. The switch expression is evaluated
exactly once.
Expression switches
ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" .
ExprCaseClause = ExprSwitchCase ":" StatementList .
ExprSwitchCase = "case" ExpressionList | "default" .
- Case expressions need not be constants and are evaluated top to bottom, left to right. The first one equal to the switch expression runs its clause; the others are skipped.
- A missing switch expression is
true. - At most one
default, in any position. - An untyped constant switch expression takes its default type first. The predeclared
untyped
nilcannot be the switch expression. The expression’s type must be comparable. - Control does not fall through by default. A
fallthroughstatement as the final non-empty statement of a clause transfers to the next clause’s first statement. It cannot appear in the last clause. - A compiler may reject duplicate constants in case expressions; current compilers reject duplicate integer, floating-point and string constants.
switch tag {
default:
s3()
case 0, 1, 2, 3:
s1()
case 4, 5, 6, 7:
s2()
}
switch x := f(); { // missing switch expression means "true"
case x < 0:
return -x
default:
return x
}
switch {
case x < y:
f1()
case x < z:
f2()
case x == 4:
f3()
}
Type switches
TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" .
TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
TypeCaseClause = TypeSwitchCase ":" StatementList .
TypeSwitchCase = "case" TypeList | "default" .
- The guard
x.(type)uses the keywordtype;xmust be of interface type and not a type parameter. Each non-interface type listed must implement the type ofx. Listed types must all be different. - With a short declaration in the guard, the variable is declared at the end of each clause’s TypeSwitchCase in that clause’s implicit block. In a clause listing exactly one type, the variable has that type; otherwise it has the type of the expression in the guard.
- A
case nilmatches a nil interface value. At most one is allowed. - A type parameter or generic type may be used as a case type. If an instantiation duplicates another entry, the first matching case is chosen.
fallthroughis not permitted in a type switch.
switch i := x.(type) {
case nil:
printString("x is nil") // type of i is type of x
case int:
printInt(i) // type of i is int
case float64:
printFloat64(i) // type of i is float64
case func(int) float64:
printFunction(i) // type of i is func(int) float64
case bool, string:
printString("type is bool or string") // type of i is type of x
default:
printString("don't know the type") // type of i is type of x
}
For statements
ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
Condition = Expression .
ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] .
InitStmt = SimpleStmt .
PostStmt = SimpleStmt .
RangeClause = [ ExpressionList "=" | IdentifierList ":=" ] "range" Expression .
Single condition and for clause
for a < b {
a *= 2
}
for i := 0; i < 10; i++ {
f(i)
}
for {
// forever, until break or return
}
while; for covers all loopsThe init statement may be a short variable declaration; the post statement must not be.
Any part of the clause may be empty, but the semicolons are needed unless there is only a
condition. An absent condition means true.
Per-iteration variables (Go 1.22). Each iteration of a three-clause loop has its own copy of the variables declared by the init statement. The variable for each later iteration is declared just before the post statement runs and is initialised to the value of the previous iteration’s variable. Before Go 1.22 all iterations shared one set of variables, which is what a closure would see.
var prints []func()
for i := 0; i < 5; i++ {
prints = append(prints, func() { println(i) })
i++
}
for _, p := range prints {
p()
}
// Go 1.22 and later prints 1, 3, 5.
// Before Go 1.22 the same program prints 6, 6, 6.
Range clause
A range clause iterates over the elements of its range expression. The
expression is evaluated once before the loop, unless there is at most one iteration
variable and x or len(x) is constant. Function calls on the left
are evaluated once per iteration.
| Range expression | Type | 1st value | 2nd value | Since |
|---|---|---|---|---|
| Array or slice | [n]E, *[n]E, []E | index int | a[i], type E | 1.0 |
| String | String type | index int | rune | 1.0 |
| Map | map[K]V | key K | m[k], type V | 1.0 |
| Channel | chan E, <-chan E | element E | none | 1.0 |
| Integer | Integer type, or untyped int | value | none | 1.22 |
| Function, 0 values | func(yield func() bool) | none | none | 1.23 |
| Function, 1 value | func(yield func(V) bool) | value V | none | 1.23 |
| Function, 2 values | func(yield func(K, V) bool) | key K | value V | 1.23 |
- A channel or integer range allows at most one iteration variable; a function allows as many as its signature gives; others up to two.
- If the last iteration variable is blank, the clause is the same as without it. Since
Go 1.4 a range may have no variables at all:
for range ch { }. - Variables declared with
:=are new in each iteration (Go 1.22). Without:=they must already exist and are assigned to as in an assignment statement.
Arrays and slices
Indexes run upward from 0. With at most one variable the loop runs from 0 to
len(a)-1 without indexing the array. A nil slice has no iterations.
Strings
The loop decodes UTF-8. The index is the byte offset of each code point and the value is
that code point, a rune. An invalid UTF-8 sequence gives the replacement
character 0xFFFD and advances one byte.
Maps
The iteration order is not specified and may differ between iterations. An entry removed before it is reached is not produced. An entry added during the loop may or may not be produced. A nil map has no iterations.
Channels
Iteration yields the values sent until the channel is closed. Ranging over a nil channel blocks forever.
Integers
for i := range n (Go 1.22) yields 0 to n-1 in
order. If n has an integer type, the values have that type. If it is an
untyped integer constant, the type comes from the iteration variable: a pre-existing
variable’s type, which must be an integer type, or otherwise the constant’s default type.
If n <= 0, there are no iterations.
for i := range 10 {
f(i) // i is an int, 0 to 9
}
var u uint8
for u = range 256 { // invalid: 256 cannot be assigned to uint8
}
for range 1e3 { // invalid: 1e3 is a floating-point constant
}
Functions
Range over functions (Go 1.23) calls the range expression f with a new,
synthesised yield function. Each call of yield before
f returns supplies the values for one run of the loop body. After each
iteration yield returns true. If the body ends the loop, such as with
break, yield returns false and must not be called again. The
yield function cannot be variadic. The iter package defines
iter.Seq and iter.Seq2 for these signatures.
// fibo generates the Fibonacci sequence.
fibo := func(yield func(x int) bool) {
f0, f1 := 0, 1
for yield(f0) {
f0, f1 = f1, f0+f1
}
}
// print the Fibonacci numbers below 1000:
for x := range fibo {
if x >= 1000 {
break
}
fmt.Printf("%d ", x)
}
Go statements
GoStmt = "go" Expression .
Starts a function or method call as an independent goroutine. The expression must be a call and cannot be parenthesised. See Concurrency.
Select statements
SelectStmt = "select" "{" { CommClause } "}" .
CommClause = CommCase ":" StatementList .
CommCase = "case" ( SendStmt | RecvStmt ) | "default" .
RecvStmt = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr .
RecvExpr = Expression .
select chooses among communication operations. Its behaviour is described on the
Concurrency page.
Return statements
ReturnStmt = "return" [ ExpressionList ] .
Ends the function, optionally giving result values. Deferred functions run after the results
are set and before the function returns. A function with results can return them in three
ways: an explicit list, a single call to a multi-valued function, or an empty
return with named result parameters. A compiler may reject an empty
return if a different entity with the same name as a result parameter is in
scope at that point.
Break, continue and goto
| Statement | Grammar | Effect |
|---|---|---|
break | "break" [ Label ] | Ends the innermost for, switch or select in the same function. A label must be that of an enclosing one of these, and that is the statement ended |
continue | "continue" [ Label ] | Starts the next iteration of the innermost for. A label must be that of an enclosing for |
goto | "goto" Label | Transfers control to the labelled statement in the same function. It must not cause variables to come into scope that were not in scope at the goto, and cannot jump into a block from outside it |
fallthrough | "fallthrough" | Transfers to the first statement of the next clause of an expression switch; only as the final non-empty statement of a clause |
OuterLoop:
for i = 0; i < n; i++ {
for j = 0; j < m; j++ {
switch a[i][j] {
case nil:
state = Error
break OuterLoop
case item:
state = Found
break OuterLoop
}
}
}
break leave several levelsDefer statements
DeferStmt = "defer" Expression .
Schedules a function or method call to run when the surrounding function returns. See Functions and methods.