Python basics and CLI cheatsheet: core syntax, f-strings, comprehensions, pathlib, venv, pip, …
Go (Golang) Cheatsheet Go (Golang) Cheatsheet

Summary
Docker, Kubernetes, Terraform, and half the CLIs I touch daily are written in Go, so it became my default for tooling too. These are the notes I wish I’d had when I started: toolchain commands, syntax I keep forgetting, and the concurrency patterns that actually come up in DevOps work.
Toolchain
Docs: go command on pkg.go.dev
go mod init github.com/karan/myapp # Start a module
go mod tidy # Add missing / drop unused deps
go get github.com/spf13/cobra@latest # Add or upgrade a dependency
go run . # Compile + run current package
go build -o bin/myapp ./cmd/myapp # Build a binary
go test ./... # Test everything, recursively
go test -run TestParse -v ./internal/... # One test, verbose
go test -race -cover ./... # Race detector + coverage
go vet ./... # Static analysis
gofmt -l -w . # Format (or: go fmt ./...)
go install golang.org/x/tools/cmd/goimports@latest # Install a tool to $GOBIN
GOOS=linux GOARCH=arm64 go build -o myapp-arm64 . # Cross-compile
go build -ldflags="-s -w" . # Strip symbols, smaller binary
Static cross-compiled binaries are why Go containers are tiny; the multi-stage build in my Docker Cheatsheet shows the payoff.
Expand your knowledge with Docker Cheatsheet
Syntax Essentials
Docs: The Go language specification at go.dev
Deepen your understanding in Python Basics & CLI Cheatsheet
Types, Variables, Slices, Maps
var count int = 10 // explicit
name := "karan" // inferred, function scope only
const MaxRetries = 3 // constants: untyped until used
nums := []int{1, 2, 3} // slice
nums = append(nums, 4)
sub := nums[1:3] // [2 3] - shares backing array
ports := map[string]int{"http": 80, "https": 443}
ports["ssh"] = 22
v, ok := ports["ftp"] // ok == false: key absent
delete(ports, "ssh")
for i, n := range nums { fmt.Println(i, n) } // map range order is random
Structs, Methods, Interfaces
type Server struct {
Host string
Port int
tags []string // lowercase = unexported
}
// Value receiver: gets a copy. Pointer receiver: can mutate.
func (s Server) Addr() string { return fmt.Sprintf("%s:%d", s.Host, s.Port) }
func (s *Server) AddTag(t string) { s.tags = append(s.tags, t) }
type Notifier interface {
Notify(msg string) error
}
// Interfaces are satisfied implicitly - no "implements" keyword.
type SlackNotifier struct{ Webhook string }
func (s SlackNotifier) Notify(msg string) error { return post(s.Webhook, msg) }
func alert(n Notifier, msg string) error { return n.Notify(msg) }
Errors & Defer
f, err := os.Open("config.yaml")
if err != nil {
return fmt.Errorf("opening config: %w", err) // %w wraps for errors.Is/As
}
defer f.Close() // runs when the function returns, LIFO order
if errors.Is(err, os.ErrNotExist) { /* fall back to defaults */ }
var pathErr *os.PathError
if errors.As(err, &pathErr) { fmt.Println(pathErr.Path) }
var ErrNotFound = errors.New("not found") // sentinel error
Goroutines & Channels
Docs: Effective Go on go.dev
Explore this further in Kubernetes Cheatsheet
go doWork() // fire-and-forget goroutine
ch := make(chan string) // unbuffered: send blocks until receive
buf := make(chan int, 10) // buffered: blocks only when full
ch <- "ping"; msg := <-ch // send / receive
close(ch) // sender closes; receivers range safely
for msg := range ch { fmt.Println(msg) } // loop until channel closed
select
select {
case msg := <-ch:
fmt.Println("got", msg)
case <-time.After(2 * time.Second):
fmt.Println("timeout")
case <-ctx.Done():
return ctx.Err()
}
WaitGroup
var wg sync.WaitGroup
for _, host := range hosts {
wg.Add(1)
go func(h string) {
defer wg.Done()
checkHealth(h)
}(host)
}
wg.Wait()
Context Cancelation
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
resp, err := http.DefaultClient.Do(req) // aborts when ctx expires
// In workers, select on ctx.Done() alongside your jobs channel and
// return ctx.Err() when it fires - same pattern as the select above.
go test -race ./... in CI. The race detector catches shared-memory bugs that pass every normal test run. The classic one is goroutines appending to a shared slice without a mutex.Table-Driven Tests
Docs: testing package on pkg.go.dev
Discover related concepts in Kubernetes Cheatsheet
func TestParsePort(t *testing.T) {
tests := []struct {
name string
input string
want int
wantErr bool
}{
{"plain", "8080", 8080, false},
{"with colon", ":443", 443, false},
{"garbage", "abc", 0, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParsePort(tt.input)
if (err != nil) != tt.wantErr {
t.Fatalf("err = %v, wantErr %v", err, tt.wantErr)
}
if got != tt.want {
t.Errorf("got %d, want %d", got, tt.want)
}
})
}
}
Generics (Quick Example)
Docs: Generics tutorial on go.dev
Uncover more details in Docker Cheatsheet
func Map[T, U any](in []T, f func(T) U) []U {
out := make([]U, len(in))
for i, v := range in {
out[i] = f(v)
}
return out
}
func Max[T cmp.Ordered](a, b T) T { if a > b { return a }; return b }
names := Map(servers, func(s Server) string { return s.Addr() })
Formatting Verbs
Docs: fmt package on pkg.go.dev
Journey deeper into this topic with Docker Cheatsheet
| Verb | Meaning | Example output |
|---|---|---|
%v | Default format | {web 8080} |
%+v | Struct with field names | {Host:web Port:8080} |
%#v | Go syntax representation | main.Server{Host:"web", ...} |
%T | Type of the value | main.Server |
%d | Integer (base 10) | 8080 |
%s | String | web |
%q | Quoted string | "web" |
%f / %.2f | Float / 2 decimals | 3.14 |
%x | Hex | 1f90 |
%w | Wrap error (fmt.Errorf only) | - |
Common Stdlib Snippets
net/http Server
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /healthz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
})
srv := &http.Server{Addr: ":8080", Handler: mux, ReadTimeout: 5 * time.Second}
log.Fatal(srv.ListenAndServe())
}
JSON Marshal / Unmarshal
type Alert struct {
Name string `json:"name"`
Severity string `json:"severity,omitempty"`
FiredAt time.Time `json:"fired_at"`
}
b, err := json.Marshal(alert) // struct → []byte
err = json.Unmarshal(b, &alert) // []byte → struct
err = json.NewDecoder(r.Body).Decode(&alert) // straight from an io.Reader
os/exec
out, err := exec.Command("kubectl", "get", "pods", "-o", "json").Output()
if err != nil {
var exitErr *exec.ExitError
if errors.As(err, &exitErr) {
log.Printf("exit %d: %s", exitErr.ExitCode(), exitErr.Stderr)
}
}
cmd := exec.CommandContext(ctx, "sh", "-c", "long-running-task") // killable via ctx
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
err = cmd.Run()
time
now := time.Now()
now.Format(time.RFC3339) // 2025-07-23T09:09:00Z
t, _ := time.Parse("2006-01-02", "2025-07-23") // reference date layout
elapsed := time.Since(start)
ticker := time.NewTicker(30 * time.Second) // defer ticker.Stop()
for range ticker.C { poll() }
Goroutines are a different world from Python’s GIL-constrained threads. If you work in both languages, my Python Threading & Concurrency Cheatsheet makes a handy side-by-side.
Enrich your learning with Ansible Cheatsheet
Related Cheatsheets
- Python Threading & Concurrency is the contrast case: the GIL, ThreadPoolExecutor, and asyncio next to goroutines and channels
- Docker has the multi-stage builds that shrink a Go binary into a scratch image, plus the run flags and compose reference
- Kubernetes is where Go tooling lives in production: kubectl reference, manifest skeletons, rollouts, and debugging
There’s more in the Languages group, or start from the whole cheatsheet library.
Similar Articles
Related Content
More from development
Quick-reference Bash basics cheatsheet: variables, parameter expansion, conditionals, loops, arrays, …
Python threading and concurrency cheatsheet: Thread, Lock, Queue, ThreadPoolExecutor, …
You Might Also Like
No related topic suggestions found.
