A first Go program needs one command-line tool, a go.mod file and a package called main. Here is what go run, go build, gofmt and go vet each do, and why Go refuses to build code with an unused import.
Every Go variable starts with a zero value, numbers never convert on their own, and constants are more flexible than variables. Learn var, :=, sized integers, overflow, iota and the Printf verbs for inspecting values.
Go gets by with if, one loop keyword called for, and a switch that doesn’t fall through. Learn each form, the Go 1.22 change that gives every loop iteration its own variable, and labelled break.
Go functions can return several values, carry variables around as closures, and schedule cleanup with defer. See how each works, including the order deferred calls run in and when their arguments are fixed.
A Go slice is a small window onto an array that holds the real values. Once you can see the window, len, cap, append and the bug where two slices change each other stop being mysterious.
A Go map stores values under keys and finds them by hashing. Learn why a missing key gives the zero value, why writing to a nil map panics, and why the iteration order changes from run to run.
A Go string is a read-only row of bytes, usually UTF-8. Once you see that, len counting bytes, indexing giving a byte, range giving runes, and a slice that splits a character in half all make sense.
Go structs are values, so every assignment and every call copies them. Pointers let you share one struct instead, and pointer receivers are how methods change the value they’re called on.
A Go interface is a list of methods, and any type with those methods satisfies it without saying so. Learn method sets, Stringer, io.Reader, type switches, and why an error holding a nil pointer isn’t nil.
Go errors are plain values you return and check. Learn to wrap them with context, find the cause with errors.Is and errors.As, join several at once, and keep panic and recover for real bugs.
A Go module is a tree of packages under one go.mod file. Learn how import paths, exported names and internal folders work, then test the code with table-driven tests, subtests, examples and benchmarks.
Go generics let one function work for many types, with constraints saying which types are allowed. Iterators let a function hand out values one at a time to a for loop, and stop the moment the loop breaks.
Go decides for you whether a value lives on the stack or the heap. See how escape analysis makes that call, how to watch it with go build -gcflags=-m, how to count allocations, and what the garbage collector does next.
A goroutine is a function running alongside the rest of your program, and Go can run thousands of them at once. Learn how to start them, wait for them, avoid leaking them, and how the scheduler shares a few threads between them.
A Go channel passes values between goroutines and makes them wait for each other. Learn unbuffered and buffered channels, closing, deadlocks, nil channels, and how select waits on several at once.
Two goroutines that change the same variable without coordination produce a data race and quietly lose updates. Learn how sync.Mutex, RWMutex, atomic and Once prevent it, and how go run -race finds it.
A Go context tells every goroutine working on a job when to stop. Learn cancellation, timeouts and request values, then build a worker pool, a pipeline, fan-out, an errgroup and a semaphore that never leak.
Go’s standard library ships a production HTTP server. Learn handlers, routing with ServeMux method and path patterns, the rules of ResponseWriter, what happens to each request, and why http.Server needs timeouts.
A task-list REST API in Go with no third-party packages. Build the store, routes, safe JSON decoding, validation, status codes, middleware and slog logging, one layer at a time.
Test a Go REST API with httptest, a fake store, log assertions, the race detector and fuzzing. Then ship it with server timeouts, graceful shutdown and one static binary.