A quick-reference cheatsheet for the most commonly used Go features. Go is a statically typed, compiled language designed for simplicity and concurrency. It has no classes or inheritance โ behaviour is composed through interfaces and structs. Error handling is explicit, and goroutines make concurrent code straightforward to write.
Go is statically typed โ every variable has a type known at
compile time. The := short declaration infers the
type from the right-hand side and is the most common form inside
functions. Variables are zero-valued by default
(0, "", false,
nil), so there are no undefined surprises.
Short declaration:x := 42
(only inside functions; type is inferred; cannot redeclare in same scope)
Var declaration:var x int = 42
(zero-valued if no initializer: 0, "", false, nil; required at package level)
Multiple return values:val, err := strconv.Atoi("42")
(idiomatic way to return both a result and an error)
Blank identifier:_, err := os.Open("file")
(discards a value; Go requires every declared variable to be used)
const (
A = iota // 0
B // 1
C // 2
)
(iota resets to 0 in each const block; useful for enums)
Slices are the primary sequence type โ a view over an underlying
array with a length and capacity. They grow automatically via
append. Maps are hash tables with O(1) average
lookup. Both are reference types: assigning a slice or map copies
the header, not the data. Always use make or a
literal to initialise a map before writing to it.
Slice literal:s := []int{1, 2, 3}
(length and capacity both 3; backed by a new array)
Make slice:s := make([]int, length, capacity)
(pre-allocates backing array; avoids repeated copies on append)
Append:s = append(s, 4, 5)s = append(s, other...)
(must reassign; append may return a new slice if capacity was exceeded)
Slice of slice:s[low:high]
(shares the backing array; mutations affect the original; high is exclusive)
Map literal:m := map[string]int{"a": 1}
Make map:m := make(map[string]int)
(a nil map panics on write; always initialise with make or a literal)
Map โ comma-ok idiom:v, ok := m["key"]
(ok is false if key is absent; v is the zero value โ always check ok)
Delete from map:delete(m, "key")
(safe to call even if the key does not exist)
Go has a single loop keyword, for, which covers
C-style loops, while-style loops (for condition),
and infinite loops (for {}). range
iterates over slices, maps, strings, and channels.
defer is Go's primary cleanup mechanism โ it runs
when the enclosing function returns, in LIFO order.
for i := 0; i < n; i++ {} // C-style
for condition {} // while-style
for {} // infinite loop
for i, v := range slice {} // index + value
for k, v := range m {} // map key + value
for _, v := range slice {} // discard index
(range over a string yields runes, not bytes)
If with init statement:if err := doWork(); err != nil {
(err is scoped to the if/else block โ keeps error handling local)
switch x {
case 1, 2:
fmt.Println("one or two")
default:
fmt.Println("other")
}
(no implicit fallthrough; use the fallthrough keyword explicitly if needed)
Defer:defer f.Close()
(arguments are evaluated immediately; body runs at function exit in LIFO order)
Functions are first-class values in Go โ they can be assigned to variables, passed as arguments, and returned from other functions. Multiple return values replace exceptions for expected errors. Closures capture variables by reference, so mutations inside the closure affect the outer variable.
Named return values:func divide(a, b float64) (result float64, err error) {
(naked return returns named values; useful for short functions, avoid in long ones)
Variadic:func sum(nums ...int) int {sum(1, 2, 3) / sum(nums...)
(nums is a slice inside the function; spread an existing slice with ...)
First-class functions:fn := func(x int) int { return x * 2 }
(function types are comparable; useful for callbacks and strategy pattern)
adder := func(x int) func(int) int {
return func(y int) int { return x + y }
}
add5 := adder(5)
add5(3) // 8
(x is captured by reference โ mutations in the closure affect it)
Go uses composition over inheritance. Structs hold data; methods
are defined separately on types. Interfaces are satisfied
implicitly โ any type that implements the required methods
qualifies, with no implements keyword. Use
pointer receivers when the method needs to mutate the struct or
when copying would be expensive.
type Point struct {
X, Y float64
}
p := Point{X: 1.0, Y: 2.0}
p.X = 3.0
(unset fields are zero-valued; use field names in literals for clarity)
Methods (value vs pointer receiver):func (p Point) Dist() float64 {}func (p *Point) Scale(f float64) {}
(value receiver = copy; pointer receiver = mutates original; be consistent on a type)
type Stringer interface {
String() string
}
// any type with String() string satisfies this
// no "implements" keyword needed
Type assertion:s, ok := val.(string)
(ok is false if the assertion fails; without ok it panics on mismatch)
switch v := i.(type) {
case string:
fmt.Println("string:", v)
case int:
fmt.Println("int:", v)
default:
fmt.Printf("unknown: %T\n", v)
}
(v is typed to the matched case; use default to handle unknown types)
In Go, errors are values โ functions return them as a second
return value and callers check immediately. This makes the happy
path and error path explicit in the code. Use %w to
wrap errors so callers can inspect the cause with
errors.Is and errors.As without
depending on string matching.
result, err := doSomething()
if err != nil {
return fmt.Errorf("context: %w", err)
}
(%w wraps the original error; %v includes it in the message but doesn't wrap)
errors.Is / errors.As:errors.Is(err, os.ErrNotExist)errors.As(err, &target)
(both unwrap the error chain; Is checks identity, As extracts a typed value)
type NotFoundError struct{ Name string }
func (e *NotFoundError) Error() string {
return e.Name + " not found"
}
(implement the error interface by defining Error() string)
Goroutines are lightweight threads managed by the Go runtime โ
you can run thousands concurrently. Channels are typed conduits
that let goroutines communicate safely. The Go mantra is
"do not communicate by sharing memory; share memory by
communicating". Use sync.WaitGroup to wait for
goroutines to finish and sync.Mutex when you must
share state directly.
Goroutine:go func() { ... }()
(starts a new goroutine; the calling goroutine continues immediately)
Channel:ch := make(chan int)ch <- 42 (send) / v := <-ch (receive)
(unbuffered: send blocks until receiver is ready, and vice versa)
Buffered channel:ch := make(chan int, 10)
(send blocks only when buffer is full; useful for decoupling producers and consumers)
select {
case v := <-ch1:
fmt.Println("received", v)
case ch2 <- x:
fmt.Println("sent")
default:
fmt.Println("no channel ready")
}
(picks a ready case at random if multiple are ready; default makes it non-blocking)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
doWork()
}()
wg.Wait()
(Add before the goroutine starts; Done via defer to handle panics)
var mu sync.Mutex
mu.Lock()
defer mu.Unlock()
// critical section
(protect shared state; defer unlock ensures release even on panic)
The Go standard library is extensive and high-quality. Most everyday tasks โ HTTP, JSON, file I/O, string manipulation, cryptography โ need no external packages. Packages are imported by their full path; only the last element is used as the identifier in code.
fmt verbs:fmt.Sprintf("%s=%d", k, v)fmt.Fprintf(os.Stderr, "err: %v\n", err)
(%v = default, %+v = with field names, %#v = Go syntax, %T = type)
strings package:strings.Contains / HasPrefix / HasSuffixstrings.Split / Join / TrimSpace / ToLowerstrings.Builder for efficient concatenation
(strings.Builder avoids the O(nยฒ) cost of repeated + concatenation)
strconv:strconv.Itoa(42) / strconv.Atoi("42")strconv.FormatFloat(f, 'f', 2, 64)
(Atoi returns (int, error); ParseInt/ParseFloat give more control)
os.Args / os.Exit / os.Getenv:os.Args[1:]os.Exit(1)val := os.Getenv("HOME")
(os.Exit skips deferred functions โ prefer returning an error when possible)
log.Fatal / log.Printf:log.Fatalf("open %s: %v", path, err)
(Fatal calls os.Exit(1) after logging; use log/slog for structured logging)