Comprehensive Go language cheatsheet, written to be something you can actually keep open while coding.
It includes core syntax, language rules, standard patterns, and essential “Go-isms”.
- Program Structure
- Variables & Constants
- Primitive Types
- Operators
- Control Flow
- Functions
- Pointers
- Arrays
- Slices
- Maps
- Structs
- Methods & Receivers
- Interfaces
- Generics
- Error Handling
defer,panic,recover- Concurrency
- Channels
- Packages & Modules
- Visibility & Naming
- Memory & Zero Values
- Common Gotchas
- Idiomatic Go Rules
package main
import "fmt"
func main() {
fmt.Println("Hello, Go")
}- Every executable has
package main - Entry point is
func main() - Imports are explicit
x := 10var x int = 10
var y = 20
var z intconst Pi = 3.14
const (
A = 1
B = 2
)- Constants are compile-time
- No
constslices, maps, or structs
int, int8, int16, int32, int64
uint, uint8, uint16, uint32, uint64
float32, float64
complex64, complex128byte // uint8
rune // int32 (Unicode)bool
string+ - * / %== != < <= > >=&& || !& | ^ << >> &^= += -= *= /= %=- ❌ No ternary operator
- ❌ No operator overloading
if x > 0 {
}With initializer:
if v := get(); v > 0 {
}for i := 0; i < 10; i++ {}
for condition {}
for {}Range:
for i, v := range slice {}
for k, v := range map {}switch x {
case 1:
case 2:
default:
}Type switch:
switch v := x.(type) {
case int:
case string:
}func add(a int, b int) int {
return a + b
}func f() (int, error) {
return 0, nil
}func f() (result int) {
result = 10
return
}var x int
p := &x
fmt.Println(*p)- No pointer arithmetic
- Used for mutation & performance
- Methods often use pointer receivers
var a [3]int
b := [3]int{1,2,3}- Fixed length
- Value types
- Rarely used directly
s := []int{1,2,3}
s = append(s, 4)s[low:high]dst := make([]int, len(src))
copy(dst, src)m := map[string]int{
"a": 1,
}Lookup:
v, ok := m["a"]Delete:
delete(m, "a")- Reference type
- Not thread-safe
- Iteration order is random
type User struct {
ID int
Name string
}Construction:
u := User{ID: 1, Name: "Jon"}Anonymous:
x := struct{ A int }{A: 1}func (u User) Name() string {}
func (u *User) Rename(n string) {}Rules:
- Value receiver → copy
- Pointer receiver → mutate
- Be consistent
type Reader interface {
Read([]byte) (int, error)
}Implicit implementation:
type File struct{}
func (File) Read([]byte) (int, error) {}Empty interface:
var x anyfunc Max[T comparable](a, b T) T {
if a > b {
return a
}
return b
}Constraints:
type Number interface {
~int | ~float64
}- Powerful but intentionally limited
- No specialization or inheritance
v, err := do()
if err != nil {
return err
}Custom errors:
errors.New("msg")
fmt.Errorf("msg: %w", err)Error wrapping:
errors.Is(err, target)
errors.As(err, &target)defer f()- Runs at function exit
- LIFO order
panic("fatal")defer func() {
if r := recover(); r != nil {
}
}()- Only works inside deferred functions
- Use sparingly
go doWork()- Lightweight
- Thousands are fine
ch := make(chan int)Send / Receive:
ch <- 1
x := <-chBuffered:
ch := make(chan int, 10)Close:
close(ch)Select:
select {
case v := <-ch:
default:
}Init module:
go mod init example.com/appImport:
import "fmt"
import "example.com/pkg"- One module = many packages
go.sumis checksums, not lockfile
func Public()
func private()- Uppercase = exported
- Lowercase = package-private
Zero values:
0, false, "", nilSafe defaults:
var s []int // nil but usableEscape analysis decides stack vs heap.
nilinterfaces ≠nilvalues- Loop variable capture in goroutines
- Shadowing with
:= - Map iteration order is random
- JSON tags must match exactly
- Slices share backing arrays
- Prefer clarity over cleverness
- Avoid deep abstraction
- Explicit error handling
- Small interfaces
- Composition over inheritance
- One obvious way to do things
Go is:
- Simple
- Explicit
- Fast
- Predictable
It rewards discipline and punishes cleverness.
- author: Jon LaBelle
- date: February 1, 2026
- source: https://jonlabelle.com/snippets/view/markdown/go-golang-language-cheatsheet