πΉ 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 stringPointers
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) // 8Defer
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 indexswitch
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 countsSlices (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 elementsCommon 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 mapIterate & 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-derefMethods
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 methodJSON 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 forgetsync.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 donesync.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+emptyselect
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.3Generic 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