logo

Go Cheatsheet

Last Updated: 2024-01-14

go command

  • go build: compile, but doesn't run or install. (It saves the compiled package in the local build cache.)
  • go run: compile and run; doesn't generate an executable binary.
    • to run with multiple files in a package/folder: go run path/to/*.go.
  • go install: compile, and put the executable binary in $HOME/go/bin.
  • go list -f '{{.Target}}': discover the install path.
  • go list -m all: list the current module and all its dependencies.
  • go get: used to build and install packages, now dedicated to adjusting dependencies in go.mod. Use go install to build and install.
  • go clean -cache: clean up GOCACHE.
  • go tool
    • if you see go tool: no such tool "6g": go tool 6g was renamed to go tool compile

-gcflags flag accepts list of flags and pass them to go tool compile. To check all available flags: go tool compile -help, e.g. -m for printing optimization decisions

$ go build -gcflags='-m=2' main.go

env

  • GOBIN: if set, binaries are installed to that directory.
  • GOPATH: if set, binaries are installed to the bin subdirectory of the first directory in the GOPATH list.
  • GOMODCACHE: the module cache; check by go env GOMODCACHE; default to GOPATH/pkg/mod.
  • GOCACHE: the build cache; check by go env GOCACHE.
    • default on Linux: ~/.cache/go-build/.
    • default on macOS: ~/Library/Caches/go-build.

GOPATH

Default: $HOME/go or %USERPROFILE%\go.

Structure:

  • GOPATH/bin: compiled binaries.
  • GOPATH/pkg/mod: the "module cache", downloaded (unzipped) source code.
  • GOPATH/pkg/mod/cache/download: downloaded .zip and .mod files.
  • GOPATH/pkg/mod/cache/download/sumdb: files downloaded from a checksum database.

When using modules, GOPATH is no longer used for resolving imports. No more GOPATH/src.

Tools

  • gofmt: format.
  • golint: lint.
  • gopls: "Go Please", the official Go language server. Used by IDEs, not by the users directly.

Array / Slice

// primes is an array
primes := [6]int{2, 3, 5, 7, 11, 13}

// s is a slice: [3 5 7]
var s []int = primes[1:4]

// slice literals
[]bool{true, true, false}

// get length
len(s)

// get capacity (num of elements in the underlying array,
// counting from the first element in the slice)
cap(s)

// if len < cap, the slice can be extended
s = s[:4]

// Creating a slice with make
b := make([]int, 0, 5) // len(b)=0, cap(b)=5

// append single
var s []int
s = append(s, 1)

// append multiple
x := []int{1,2,3}
y := []int{4,5,6}
x = append(x, y...)

// remove last element
if len(slice) > 0 {
    slice = slice[:len(slice)-1]
}

// Use copy to move the upper part of the slice out of the way and open a hole.
copy(slice[index+1:], slice[index:])

Map

// create
m := make(map[string]int)

// get
v := m["Answer"]
v, ok := m["Answer"]

// set
m["Answer"] = 42

// delete
delete(m, "Answer")

// contains key
val, ok := myMap["foo"]
// If the key exists
if ok {
    // Do something
}
// or
if item, ok := m[key]; ok {
  // ...
}

JSON

Use encoding/json:

import (
	"encoding/json"
)

type User struct {
	Name        string  `json:"name"`
	Password    string  `json:"-"`
	Description string  `json:"description,omitempty"`
}
  • -: ignore the field
  • omitempty: field will not be encoded if empty

Marshal

u := &User{
    Name:      "user_name",
    Password:  "user_password",
}

out, err := json.Marshal(u)
// or
out, err := json.MarshalIndent(u, "", "  ")

Unmarshal

// b byte[]
if err := json.Unmarshal(b, &u); err != nil {
    return err
}

String

  • Double quote ("): need to escape special characters, e.g. "\n" is a single character
  • backtick (`): raw string literals, no escape.
import "strings"

// String literals
str := "Hello"
str := `Multiline
string`

// Prefix / Suffix
strings.HasPrefix("string", "prefix")
strings.HasSuffix(s, "!")

// Split
strings.Split(str1, ",")

// Join
strings.Join(arr, ",")

// Concat
result := str1 + str2
result := fmt.Sprintf("%s%s", str1, str2)
str1 += str2

// Replace
result := strings.Replace(str, old, new, -1)

// Contains
b := strings.Contains(str, substr)

Type conversions

// int to float
f := float64(i)

// bytes to string
myString := string(myBytes[:])

Loop

for loop for everything; no while loop.

// loop an array / slice
for i, val := range a {
    // ...
}

// loop a map
for key := range m {
    // ...
}

// traditional for loop
for i := 0; i <= 10; i++ {
    // ...
}

// while loop
for a != b {
    // ...
}

// loop until the channel is closed
for i := range ch {
    // ···
}

Goroutines

Channel

// create a channel
ch := make(chan int)
// create a buffered channel
ch := make(chan int, 2)

ch <- 1

<-ch

// close a channel
close(ch)

// check if ch is closed (closed if ok is false)
v, ok := <- ch

WaitGroup

import "sync"

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 5; i++ {
        wg.Add(1)
        i := i
        go func() {
            defer wg.Done()
            doSomething(i)
        }
    }
    wg.Wait()
}

Error handling

if err := foo(); err != nil {
  // ...
}

OOP

Interface

type Shape interface {
  Area() float64
  Perimeter() float64
}

Struct

type Vertex struct {
  X, Y float64
}

Methods

func (v *Vertex) Scale(f float64) {
  v.X = v.X * f
  v.Y = v.Y * f
}

Tree

type Tree struct {
    Left  *Tree
    Value int
    Right *Tree
}

If-else

() is optional, {} is required.

if a < 0 {
	// ...
} else {
  // ...
}

IO

// recursively visit
filepath.Walk()

// get parent
filepath.Dir()

Math

Go has math.Max()/math.Abs() to compare 2 numbers, but only for float.

Constants / Variables

const x, y = 10, 20
const (
    a = 1
    b = 2
)