Go Cheatsheet

Complete Go reference. Hit Ctrl+P to print.

Variables & Types

var x int = 42Explicit variable declaration
x := 42Short variable declaration - type inferred, only inside functions
var x, y int = 1, 2Declare multiple variables
x, y := 1, "hello"Multiple short declarations
const Pi = 3.14Constant - evaluated at compile time
const ( A = 1; B = 2 )Grouped constants
const ( A = iota; B; C )iota - auto-incrementing const: 0, 1, 2
int / int8 / int16 / int32 / int64Signed integers
uint / uint8 / uint16 / uint32 / uint64Unsigned integers
float32 / float64Floating point
complex64 / complex128Complex numbers
booltrue or false
stringImmutable UTF-8 byte sequence
byteAlias for uint8
runeAlias for int32 - represents a Unicode code point
anyAlias for interface{} - accepts any type (Go 1.18+)
var p *int = &xPointer - & takes address, * dereferences
p := new(int)Allocate zeroed value and return pointer

Strings

"hello"String literal - double quotes, supports escape sequences
`raw\nstring`Raw string literal - backticks, no escape processing, can span lines
"a" + "b"Concatenation
len(s)Byte length (not character count - use utf8.RuneCountInString for runes)
s[0]Byte at index (returns byte, not rune)
s[1:4]Byte slice
for i, r := range s { }Iterate over Unicode code points (runes)
[]byte(s) / string(b)Convert string to/from byte slice
[]rune(s) / string(r)Convert string to/from rune slice
fmt.Sprintf("Hello, %s! You are %d.", name, age)Format string
fmt.Sprintf("%v", x)%v - default format; %+v includes field names; %#v is Go syntax
strings.Contains(s, "sub")True if substring found
strings.HasPrefix(s, "pre") / strings.HasSuffix(s, "suf")Check prefix / suffix
strings.Index(s, "sub")First byte index of substring (-1 if not found)
strings.ToUpper(s) / strings.ToLower(s)Change case
strings.TrimSpace(s) / strings.Trim(s, "!")Strip whitespace / specific characters
strings.Split(s, ",") / strings.Join(parts, ",")Split / join
strings.Replace(s, "a", "b", -1)Replace all occurrences (-1 = all)
strconv.Itoa(42) / strconv.Atoi("42")Int to string / string to int

Slices & Maps

[3]int{1, 2, 3}Array - fixed size, part of the type
[]int{1, 2, 3}Slice literal - dynamic, reference to underlying array
make([]int, 5)Slice of length 5, capacity 5
make([]int, 0, 10)Slice of length 0, capacity 10
len(s) / cap(s)Length / capacity of slice
s = append(s, 4)Append element - may allocate new backing array
s = append(s, other...)Append all elements of another slice
s[1:3]Sub-slice - shares memory with original
copy(dst, src)Copy elements - returns number copied
for i, v := range s { }Iterate slice with index and value
for _, v := range s { }Iterate ignoring index
map[string]int{"a": 1}Map literal
m := make(map[string]int)Create empty map
m["key"] = 1Set value
v := m["key"]Get value - returns zero value if key absent
v, ok := m["key"]Safe get - ok is false if key absent
delete(m, "key")Remove key
for k, v := range m { }Iterate map (order not guaranteed)

Control Flow

if x > 0 { }No parentheses around condition; braces required
if x := f(); x > 0 { }if with init statement - x scoped to the if block
if x > 0 { } else if x < 0 { } else { }if / else if / else
switch x { case 1: ... case 2, 3: ... default: ... }Switch - no fallthrough by default
switch { case x > 0: ... }Expressionless switch - like if/else chain
fallthroughExplicitly fall through to next case
for i := 0; i < 10; i++ { }C-style for loop
for x > 0 { }While-style loop
for { }Infinite loop
for i, v := range slice { }Range over slice
for k, v := range m { }Range over map
for r := range ch { }Range over channel - blocks until closed
break / continueExit loop / skip iteration
break label / continue labelBreak / continue to labelled outer loop
defer fn()Schedule fn to run when current function returns - LIFO order
defer func() { recover() }()Recover from panic in deferred function

Functions

func add(a, b int) int { return a + b }Function with same-type params shorthand
func minMax(a, b int) (int, int) { return a, b }Multiple return values
func divide(a, b float64) (float64, error) { }Idiomatic: return value + error
func sum(nums ...int) int { }Variadic - nums is []int inside the function
fn(slice...)Unpack slice as variadic args
func (result int, err error) namedReturns() { }Named return values - can use bare return
add := func(a, b int) int { return a + b }Function literal / anonymous function
func makeAdder(x int) func(int) int { return func(y int) int { return x + y } }Closure - captures outer variable
func init() { }init - runs automatically before main, once per package
func main() { }Entry point for executable packages

Structs & Interfaces

type Point struct { X, Y float64 }Struct definition
p := Point{X: 1, Y: 2}Struct literal with named fields
p := Point{1, 2}Struct literal positional - fragile, avoid
p.X / p.YAccess struct fields
pp := &Point{1, 2}Pointer to struct
pp.XGo auto-dereferences pointer for field access
func (p Point) String() string { }Value receiver method
func (p *Point) Scale(f float64) { }Pointer receiver method - can mutate p
type Animal struct { Name string }\ntype Dog struct { Animal; Breed string }Embedding - Dog inherits Animal fields and methods
type Stringer interface { String() string }Interface - satisfied implicitly (no implements keyword)
var s Stringer = MyType{}Assign concrete type to interface variable
v, ok := s.(MyType)Type assertion - ok is false if not that type
switch v := s.(type) { case int: ... case string: ... }Type switch
type Reader interface { Read(p []byte) (n int, err error) }Common io.Reader interface pattern
var _ Stringer = (*MyType)(nil)Compile-time interface satisfaction check

Goroutines & Channels

go fn(args)Launch goroutine - lightweight concurrent function
go func() { ... }()Launch anonymous goroutine
ch := make(chan int)Unbuffered channel - send blocks until receiver is ready
ch := make(chan int, 10)Buffered channel - send blocks only when buffer is full
ch <- 42Send value to channel
v := <-chReceive value from channel
v, ok := <-chReceive - ok is false if channel closed and empty
close(ch)Close channel - receivers get zero values after drain
for v := range ch { }Receive until channel is closed
select { case v := <-ch1: ... case ch2 <- v: ... default: ... }select - multiplex channel ops; default makes it non-blocking
var wg sync.WaitGroup\nwg.Add(1)\ngo func() { defer wg.Done(); ... }()\nwg.Wait()WaitGroup - wait for goroutines to finish
var mu sync.Mutex\nmu.Lock()\ndefer mu.Unlock()Mutex - protect shared state
var once sync.Once\nonce.Do(fn)Execute fn exactly once across all goroutines
atomic.AddInt64(&counter, 1)Atomic operation - lock-free increment

Error Handling

result, err := doSomething()Idiomatic: check error on every call
if err != nil { return err }Propagate error up the call stack
errors.New("something went wrong")Create a simple error value
fmt.Errorf("failed to open %s: %w", path, err)%w wraps the error for unwrapping
errors.Is(err, ErrNotFound)Check if error matches (traverses wrapped chain)
errors.As(err, &target)Check if error can be assigned to target type
errors.Unwrap(err)Return the wrapped error (or nil)
type NotFoundError struct { Name string }\nfunc (e *NotFoundError) Error() string { }Custom error type - implement the error interface
panic("something catastrophic")Panic - unwinds stack, runs deferred functions
recover()Recover from panic - only useful inside a deferred function
var ErrNotFound = errors.New("not found")Sentinel error - compare with errors.Is