🐹 Go (Golang) Cheat Sheet

Variables, structs, interfaces, goroutines, channels and generics.

πŸ”
πŸ“¦ Variables & Types
Variable declarations
var name string = "Go"    // explicit
var age  = 25             // inferred
count   := 10             // short declaration (inside func)
const Pi = 3.14159

// Multiple vars
var (
  x int    = 1
  y string = "hi"
)
Basic types
bool        // true / false
string      // UTF-8 immutable
int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64
float32  float64
complex64 complex128
byte  // alias for uint8
rune  // alias for int32 (Unicode code point)
Zero values
var i int     // 0
var f float64 // 0.0
var b bool    // false
var s string  // ""
var p *int    // nil
Type conversion
i := 42
f := float64(i)
s := strconv.Itoa(i)          // int β†’ string
n, err := strconv.Atoi("42") // string β†’ int
fmt.Sprintf("%d", i)          // formatted string
Pointers
x := 10
p := &x       // pointer to x
*p = 20       // dereference β€” x is now 20

func inc(n *int) { *n++ }
inc(&x)
πŸ”§ Functions
Basic function
func add(a, b int) int {
  return a + b
}

// Multiple return values
func divide(a, b float64) (float64, error) {
  if b == 0 { return 0, fmt.Errorf("divide by zero") }
  return a / b, nil
}
Named return values
func minMax(a, b int) (min, max int) {
  if a < b { return a, b }
  return b, a
}
Variadic & closures
func sum(nums ...int) int {
  total := 0
  for _, n := range nums { total += n }
  return total
}
sum(1, 2, 3)
sum(nums...) // spread slice

// Closure
adder := func(x int) func(int) int {
  return func(y int) int { return x + y }
}
add5 := adder(5)
add5(3) // 8
Defer
func readFile(name string) error {
  f, err := os.Open(name)
  if err != nil { return err }
  defer f.Close()  // runs when function returns
  // ...
}
πŸ”€ Control Flow
if / else
if x > 0 {
  fmt.Println("positive")
} else if x < 0 {
  fmt.Println("negative")
} else {
  fmt.Println("zero")
}

// Init statement
if v, err := getValue(); err == nil {
  fmt.Println(v)
}
for loops
// Classic
for i := 0; i < 5; i++ { }

// While-style
for n < 100 { n *= 2 }

// Infinite
for { break }

// Range
for i, v := range slice { }
for k, v := range myMap { }
for _, v := range slice { } // ignore index
switch
switch day {
case "Mon", "Tue":
  fmt.Println("early week")
case "Fri":
  fmt.Println("TGIF")
default:
  fmt.Println("midweek")
}

// No condition β€” like if/else chain
switch {
case x > 100: fmt.Println("big")
case x > 0:   fmt.Println("positive")
}
πŸ“š Arrays & Slices
Arrays (fixed size)
var a [3]int          // [0 0 0]
b := [3]int{1, 2, 3}
c := [...]int{1, 2, 3} // compiler counts
Slices (dynamic)
s := []int{1, 2, 3}
s = append(s, 4, 5)

make([]int, 5)       // len=5, cap=5
make([]int, 0, 10)   // len=0, cap=10

s[1:3]   // [2 3]  β€” slice of slice
s[:2]    // [1 2]
s[1:]    // [2 3 4 5]

copy(dst, src)  // copy elements
Common slice ops
len(s)    // length
cap(s)    // capacity

// Filter
result := s[:0]
for _, v := range s {
  if v > 2 { result = append(result, v) }
}

// Contains (Go 1.21+)
slices.Contains(s, 3) // true
πŸ—ΊοΈ Maps
Map basics
m := map[string]int{"a": 1, "b": 2}
m["c"] = 3          // set
v := m["a"]         // get (0 if missing)
v, ok := m["x"]    // ok = false if missing
delete(m, "a")      // remove

make(map[string]int)  // empty map
Iterate & check
for k, v := range m { fmt.Println(k, v) }

// Check existence
if val, exists := m["key"]; exists {
  fmt.Println(val)
}

// Go 1.21+
maps.Keys(m)    // []string of keys
maps.Values(m)  // []int  of values
πŸ—οΈ Structs
Define & instantiate
type User struct {
  ID   int
  Name string
  Age  int
}

u := User{ID: 1, Name: "Feem", Age: 30}
u.Name = "Dev"

// Pointer to struct
p := &User{Name: "Go"}
p.Name = "Golang"  // auto-deref
Methods
func (u User) Greet() string {
  return "Hi, I'm " + u.Name
}

// Pointer receiver β€” can mutate
func (u *User) Birthday() {
  u.Age++
}
Embedding (composition)
type Animal struct { Name string }
func (a Animal) Speak() string { return a.Name }

type Dog struct {
  Animal        // embedded β€” promotes fields & methods
  Breed string
}

d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Lab"}
d.Speak()  // "Rex" β€” promoted method
JSON tags
type Product struct {
  ID    int    `json:"id"`
  Name  string `json:"name"`
  Price float64 `json:"price,omitempty"`
  secret string  // unexported β€” ignored by JSON
}

data, _ := json.Marshal(p)
json.Unmarshal(data, &p)
πŸ”Œ Interfaces
Define & implement
type Stringer interface {
  String() string
}

type Dog struct{ Name string }
func (d Dog) String() string { return d.Name } // implicit β€” no "implements" keyword

var s Stringer = Dog{Name: "Rex"}
fmt.Println(s.String())
Type assertion & switch
var i interface{} = "hello"

s, ok := i.(string)  // ok = true
n, ok := i.(int)     // ok = false

switch v := i.(type) {
case string:  fmt.Println("string:", v)
case int:     fmt.Println("int:", v)
default:      fmt.Println("unknown")
}
Empty interface & any
// any = alias for interface{}
func printAll(vals ...any) {
  for _, v := range vals { fmt.Println(v) }
}
printAll(1, "two", true, 3.14)
⚠️ Error Handling
Return & check errors
result, err := doSomething()
if err != nil {
  return fmt.Errorf("doSomething: %w", err) // wrap with %w
}

// Unwrap
errors.Is(err, ErrNotFound)
errors.As(err, &myErr)
Custom error types
type NotFoundError struct {
  ID int
}
func (e *NotFoundError) Error() string {
  return fmt.Sprintf("id %d not found", e.ID)
}

// Sentinel errors
var ErrNotFound = errors.New("not found")
panic & recover
func safeDiv(a, b int) (result int, err error) {
  defer func() {
    if r := recover(); r != nil {
      err = fmt.Errorf("recovered: %v", r)
    }
  }()
  return a / b, nil  // panics if b==0
}
⚑ Goroutines
Launch goroutine
go func() {
  fmt.Println("runs concurrently")
}()

go heavyTask(data) // fire and forget
sync.WaitGroup
var wg sync.WaitGroup

for i := 0; i < 5; i++ {
  wg.Add(1)
  go func(n int) {
    defer wg.Done()
    process(n)
  }(i)
}
wg.Wait() // blocks until all done
sync.Mutex
var mu sync.Mutex
counter := 0

go func() {
  mu.Lock()
  defer mu.Unlock()
  counter++
}()
πŸ“‘ Channels
Create & send/receive
ch := make(chan int)      // unbuffered
ch := make(chan int, 10) // buffered

go func() { ch <- 42 }()  // send (blocks if full)
v := <-ch                  // receive (blocks if empty)

close(ch)                  // signal no more values
v, ok := <-ch             // ok=false when closed+empty
select
select {
case msg := <-ch1:
  fmt.Println("ch1:", msg)
case ch2 <- val:
  fmt.Println("sent to ch2")
case <-time.After(1 * time.Second):
  fmt.Println("timeout")
default:
  fmt.Println("non-blocking")
}
Range over channel
func generate(nums ...int) <-chan int {
  out := make(chan int)
  go func() {
    for _, n := range nums { out <- n }
    close(out)
  }()
  return out
}

for n := range generate(1, 2, 3) {
  fmt.Println(n)
}
🧬 Generics (Go 1.18+)
Generic function
func Map[T, U any](s []T, f func(T) U) []U {
  result := make([]U, len(s))
  for i, v := range s { result[i] = f(v) }
  return result
}

doubled := Map([]int{1,2,3}, func(n int) int { return n*2 })
Type constraints
type Number interface {
  ~int | ~int64 | ~float64
}

func Sum[T Number](s []T) T {
  var total T
  for _, v := range s { total += v }
  return total
}

Sum([]int{1, 2, 3})        // 6
Sum([]float64{1.1, 2.2})   // 3.3
Generic struct
type Stack[T any] struct{ items []T }

func (s *Stack[T]) Push(v T)  { s.items = append(s.items, v) }
func (s *Stack[T]) Pop() (T, bool) {
  if len(s.items) == 0 { var zero T; return zero, false }
  v := s.items[len(s.items)-1]
  s.items = s.items[:len(s.items)-1]
  return v, true
}
πŸ“¦ Packages & Modules
Module init & imports
go mod init github.com/user/myapp
go get github.com/some/package
go mod tidy

import (
  "fmt"
  "os"
  "strings"
  http "net/http"          // alias
  _ "github.com/lib/pq"   // side-effect import
)
Common stdlib
fmt.Printf("%s is %d\n", name, age)
fmt.Sprintf("Hello %s", name)
fmt.Errorf("wrap: %w", err)

strings.Contains(s, "sub")
strings.Split(s, ",")
strings.TrimSpace(s)
strings.ToUpper(s)

strconv.Itoa(42)        // int β†’ string
strconv.Atoi("42")      // string β†’ int

os.Getenv("HOME")
os.Args                 // CLI args