Keywords
The 25 reserved words that make up Go's grammar — declarations, control flow, types, and concurrency primitives. Unchanged since Go 1.0 and still the full set through Go 1.26.
Terminates the innermost for, switch, or select statement.
Introduces a clause in a switch or select statement.
Declares a channel type used for goroutine communication.
Declares a constant value, fixed at compile time.
Skips to the next iteration of the innermost for loop.
Specifies the default clause in a switch or select statement.
Schedules a function call to run after the surrounding function returns.
Introduces the alternative branch of an if statement.
Transfers control to the next case clause in a switch statement.
Introduces a loop; Go's only looping construct.
Declares a function, method, or function literal.
Starts a new goroutine running a function call.
Transfers control to a labeled statement in the same function.
Introduces a conditional statement.
Declares packages whose exported identifiers may be used in the file.
Declares an interface type, a set of method signatures.
Declares a map type, an unordered collection of key-value pairs.
Declares the package to which the current source file belongs.
Iterates over elements of an array, slice, string, map, channel, or integer.
Terminates a function and optionally returns values to the caller.
Waits on multiple channel communication operations.
Declares a struct type, a sequence of named fields.
Introduces a multi-way conditional statement.
Declares a new named type or type alias.
Declares one or more variables.
Examples
var, const, type, func, import, and package are the vocabulary of top-level and local declarations. Only package and import are file-scoped; the rest can appear almost anywhere.
package main
import "fmt"
const MaxRetries = 3
type Job struct {
ID int
Tries int
}
func retry(j Job) bool {
var ok bool = j.Tries < MaxRetries
return ok
}
fmt.Println(retry(Job{ID: 1, Tries: 2}))trueswitch in Go doesn't fall through by default — each case breaks automatically. fallthrough opts back in to the C-style behavior.
grade := 82
if grade >= 90 {
fmt.Println("A")
} else if grade >= 80 {
fmt.Println("B")
} else {
fmt.Println("C or lower")
}
switch {
case grade >= 90:
fmt.Println("excellent")
case grade >= 70:
fmt.Println("passing")
fallthrough
default:
fmt.Println("recorded")
}B
passing
recordedfor is Go's only loop keyword — it covers counted loops, while-style loops, and range iteration. break and continue target the innermost loop unless given a label.
sum := 0
for i := 0; i < 10; i++ {
if i%2 != 0 {
continue
}
if i > 6 {
break
}
sum += i
}
fmt.Println(sum)
fruits := []string{"fig", "kiwi", "plum"}
for i, f := range fruits {
fmt.Println(i, f)
}12
0 fig
1 kiwi
2 plumgoto jumps to a labeled statement in the same function. It can't jump into a block or over a variable declaration — the compiler rejects both.
i := 0
loop:
if i < 3 {
fmt.Println("i =", i)
i++
goto loop
}
fmt.Println("done")i = 0
i = 1
i = 2
doneThese four keywords declare Go's composite and reference-like types: fixed-shape records, method-set contracts, key-value collections, and typed communication pipes.
type Shape interface {
Area() float64
}
type Rect struct {
W, H float64
}
func (r Rect) Area() float64 { return r.W * r.H }
shapes := map[string]Shape{
"a": Rect{W: 3, H: 4},
}
fmt.Println(shapes["a"].Area())
results := make(chan float64, 1)
results <- shapes["a"].Area()
fmt.Println(<-results)12
12go launches a goroutine; select waits on whichever of several channel operations is ready first, the concurrency counterpart to switch.
ch1 := make(chan string)
ch2 := make(chan string)
go func() { ch1 <- "from ch1" }()
go func() { ch2 <- "from ch2" }()
for i := 0; i < 2; i++ {
select {
case msg := <-ch1:
fmt.Println(msg)
case msg := <-ch2:
fmt.Println(msg)
}
}from ch1
from ch2defer runs LIFO, after return has set the result but before the function actually hands control back — which is why a deferred func can still modify a named return value.
func process() (n int) {
defer func() { n *= 10 }()
defer fmt.Println("cleanup")
n = 4
return n
}
fmt.Println(process())cleanup
40In practice
range combined with continue skips completed tasks without an extra if/else branch. The named zero Task return relies on var producing the type's zero value when nothing is found.
type Task struct {
Name string
Done bool
}
func nextPending(tasks []Task) (Task, bool) {
for _, t := range tasks {
if t.Done {
continue
}
return t, true
}
var zero Task
return zero, false
}A switch with an init statement scopes t and ok to the switch itself, the same pattern used for if with an init clause.
tasks := []Task{
{Name: "design", Done: true},
{Name: "build", Done: false},
{Name: "ship", Done: false},
}
switch t, ok := nextPending(tasks); {
case !ok:
fmt.Println("nothing pending")
default:
fmt.Println("next up:", t.Name)
}$ go run main.go
next up: build