A quick reference for Go (Golang) syntax and patterns. Covers types, variables, structs, interfaces, goroutines, channels, error handling, slices, maps, and defer/panic/recover. Current through Go 1.26 (February 2026), which let new() take an expression and made the Green Tea garbage collector the default.
Types & Variables
| Syntax | Description |
|---|---|
| var x int | Declare variable with explicit type |
| var x int = 42 | Declare and initialize |
| x := 42 | Short variable declaration (inferred type) |
| const Pi = 3.14 | Constant declaration |
| int, int8, int16, int32, int64 | Signed integer types |
| uint, uint8 (byte), uint16, .. | Unsigned integer types |
| float32, float64 | Floating point types |
| string | Immutable UTF-8 string |
| bool | Boolean (true / false) |
| rune | Unicode code point (alias for int32) |
Structs
| Syntax | Description |
|---|---|
| type User struct { Name string } | Define a struct type |
| u := User{Name: "Alice"} | Create struct instance |
| u := User{} | Zero-value struct |
| u.Name | Access struct field |
| type Admin struct { User; Level int } | Embedded struct (composition) |
| func (u User) String() string | Method with value receiver — gets a copy, cannot mutate |
| func (u *User) SetName(n string) | Method with pointer receiver — use when mutating or for large structs |
| type Point struct { X, Y float64 } | Multiple fields of same type |
Interfaces
| Syntax | Description |
|---|---|
| type Reader interface { Read([]byte) } | Define an interface |
| interface{} | Empty interface (accepts any value) |
| any | Alias for interface{} (Go 1.18+) |
| v, ok := i.(string) | Type assertion with check |
| switch v := i.(type) { case string: } | Type switch |
| type ReadWriter interface { Reader; Writer } | Compose interfaces via embedding |
| var w io.Writer = &buf | Implicit interface satisfaction |
Slices & Maps
| Syntax | Description |
|---|---|
| s := []int{1, 2, 3} | Slice literal |
| s := make([]int, 0, 10) | Make slice with length 0, capacity 10 |
| s = append(s, 4, 5) | Append elements to slice |
| s[1:3] | Sub-slice (index 1 to 2) |
| len(s), cap(s) | Length and capacity |
| copy(dst, src) | Copy elements between slices |
| m := map[string]int{"a": 1} | Map literal |
| m := make(map[string]int) | Make empty map |
| v, ok := m["key"] | Map lookup with existence check |
| delete(m, "key") | Delete key from map |
Goroutines
| Syntax | Description |
|---|---|
| go f() | Launch function as goroutine |
| go func() { .. }() | Launch anonymous goroutine |
| runtime.NumGoroutine() | Get number of running goroutines |
| sync.WaitGroup | Wait for group of goroutines to finish |
| wg.Add(1) | Increment WaitGroup counter |
| wg.Done() | Decrement WaitGroup counter |
| wg.Wait() | Block until counter reaches zero |
| sync.Mutex / sync.RWMutex | Mutual exclusion locks |
Channels
| Syntax | Description |
|---|---|
| ch := make(chan int) | Unbuffered channel — send blocks until someone receives |
| ch := make(chan int, 10) | Buffered channel (capacity 10) — send blocks only when full |
| ch <- 42 | Send value to channel |
| v := <-ch | Receive value from channel |
| close(ch) | Close channel (no more sends) |
| for v := range ch { } | Iterate until channel closed |
| select { case v := <-ch: .. } | Wait on multiple channels |
| ch := make(chan<- int) | Send-only channel type |
| ch := make(<-chan int) | Receive-only channel type |
Error Handling
| Pattern | Description |
|---|---|
| if err != nil { return err } | Standard error check and propagate |
| fmt.Errorf("wrap: %w", err) | Wrap error with context (Go 1.13+) |
| errors.Is(err, target) | Check if err matches target (unwraps) |
| errors.As(err, &target) | Extract typed error from chain |
| errors.New("message") | Create simple error value |
| type MyErr struct { .. } | Custom error type (implement Error()) |
| var ErrNotFound = errors.New(..) | Sentinel error variable |
Defer, Panic & Recover
| Syntax | Description |
|---|---|
| defer f() | Schedule call to run when function returns |
| defer file.Close() | Common: close resource on exit |
| defer mu.Unlock() | Common: release lock on exit |
| panic("message") | Trigger runtime panic (unwind stack) |
| recover() | Catch panic in deferred function |
| defer func() { if r := recover(); r != nil { .. } }() | Full recover pattern |
Common gotchas
- Loop variables are per-iteration since Go 1.22 (February 2024) — the classic
go func() { use(v) }()capture bug is fixed, but only whengo.moddeclaresgo 1.22or later. Older module directives keep the old shared-variable semantics. - Reading from a nil map returns the zero value; writing to one panics.
var m map[string]intis nil — initialize withmakeor a literal before assigning. appendmay reuse the backing array: two slices from the same source can silently overwrite each other's elements while capacity remains. Force a copy withslices.Clone(Go 1.21+) when handing a sub-slice out.deferruns at function exit, not block exit — deferringf.Close()inside a loop accumulates open handles until the function returns.- A goroutine blocked forever on a channel send is a leak. Go 1.26 ships an experimental
goroutineleakpprof profile (GOEXPERIMENT=goroutineleakprofile) that finds them via the garbage collector.
Related: environment variables in Go and constants in Go (untyped constants and iota get their own gotcha list).