go run main.go★Compile + run in one step (throwaway binary).go buildCompile the package to a native binary here.go build ./...Build every package in the module tree.go test ./...Run all tests in the tree.go fmt ./...★Canonical formatting (gofmt) — non-negotiable.go vet ./...Static checks for suspicious constructs.go mod init example.com/appStart a module (createsgo.mod).go get golang.org/x/tools@latestAdd or upgrade a dependency.go install ./cmd/app@latestBuild + install a binary toGOBIN.GOOS=linux GOARCH=arm64 go buildCross-compile — one toolchain targets every OS/arch.go work init ./a ./b1.18Multi-module workspace (createsgo.work).go env GOPATH GOMODCACHEInspect the Go environment.go fix ./...1.26Apply modernizers — fully revamped.go doc fmt.PrintlnShow docs in the terminal.
package main★An executable; any other name = a library.import "fmt"Pull in a package by its import path.import ( "fmt"; "os" )Grouped imports (gofmt sorts them).import _ "net/http/pprof"Blank import: runs a package init for side effects only.func main() { ... }★The entry point ofpackage main.func init() { ... }Runs once at startup, beforemain(any file may have one).// line /* block */The two comment forms.func Public() {}exportUppercase = exported; lowercase = package-private.go run .Run the whole package (all its files).
var b bool = truetrue/falseonly.var n int = 42Platform int (64-bit on most machines); alsoint8..int64,uint...var f float64 = 3.14Alsofloat32,complex128,complex64.var s string = "hi"★Immutable, UTF-8 encoded bytes.var r rune = 'A'rune=int32 (code point);byte=uint8.var x int★Declared & zero-valued — there are no uninitialised vars.0 "" false nil★The zero values, by type.0x1f 0o17 0b1010 1_000_000 1e6Hex, octal, binary, digit-separated & scientific literals.const ( A = iota; B; C )iotaauto-increments: 0, 1, 2 — the enum pattern.const ( _ = iota; KB = 1 << (10*iota) )iotain an expression — scaled/bit-flag enums.
var x int = 5Full declaration (type optional if inferable).x := 5★Short declaration — inside functions only.a, b := 1, 2★Multiple assignment in one line.a, b = b, aSwap with no temp variable._ = f()The blank identifier discards a value.const Pi = 3.14159Compile-time constant (untyped until used).var ( x int; y string )Grouped declarations.x := 5; x := 6redeclRe-:=in the same scope is an error — use=.
+ - * / %★Arithmetic;/on ints truncates toward zero.== != < <= > >=Comparison — both sides must be the same type.&& || !Logical, short-circuiting.& | ^ &^ << >>Bitwise (&^= AND-NOT).&x *p★Address-of, and pointer dereference.x++ x--Statements, not expressions (no++x).+= -= *= ...Compound assignment.ch <- v v := <-chChannel send / receive.
s := "h\u00e9llo"Immutable, stored as UTF-8 bytes.len(s)★bytesNumber of bytes, not characters.s[i]The byte ati(auint8).for i, r := range s★Iterates runes;ijumps by rune width.[]rune(s) []byte(s)Decode to code points, or raw bytes.`raw\nstring`Backticks: no escapes, may span lines.strings.Split(s, ",")AlsoJoin,Contains,ReplaceAll,TrimSpace.var b strings.Builder; b.WriteString(x)★builderThe efficient way to concatenate in a loop.utf8.RuneCountInString(s)Count characters (runes), not bytes.fmt.Sprintf("%d-%s", n, s)Format into a string (%vfor anything).strconv.Itoa(n); strconv.Atoi("7")int ↔ string conversions.
if x > 0 { } else { }★Braces required; no parentheses.if v := f(); v > 0 { }★Init statement scoped to theif.for i := 0; i < n; i++ { }★The C-style three-clause loop.for cond { }Go's “while” — justfor.for { }Infinite loop;breakto exit.for i := range 5 { }1.22Range over an integer.for k, v := range m★Range slices, maps, strings, channels.switch x { case 1: ... }★No implicit fall-through; usefallthroughto chain.switch { case cond: ... }Tag-less switch = a clean if/else ladder.Outer: for { for { break Outer } }labelLabels letbreak/continuetarget an outer loop.goto DoneJumps to a label in the same function (rare; loops usually read better).
func add(a, b int) int { }Shared type for consecutive params.func f() (int, error)★Multiple return values — the Go signature.func f() (n int, err error)Named results (pre-declared, zero-valued).returnNaked return sends back the named results.func sum(xs ...int) intVariadic:xsis a[]intinside.sum(nums...)Spread a slice into a variadic call.f := func(x int) int { ... }★Anonymous function / closure.defer cleanup()★Schedule a call for function exit.func() func() int { ... }Closures capture surrounding variables by reference.defer func(){ err = wrap(err) }()named retA deferred closure can read & modify named return values.
if err != nil { return err }★The idiom — you'll write it everywhere.errors.New("not found")A simple sentinel error value.fmt.Errorf("read: %w", err)★Wrap an error, preserving the chain with%w.errors.Is(err, ErrNotFound)Match a wrapped sentinel error.errors.As(err, &target)Extract a concrete error type from the chain.errors.AsType[*PathErr](err)1.26Generic, type-safe, fasterAs.func (e *E) Error() stringImplementerror= one method.var ErrNotFound = errors.New("not found")★A package-level sentinel to compare against.func (e *E) Unwrap() error { return e.inner }Expose the wrapped error soIs/Ascan walk it.errors.Join(e1, e2)Combine several errors into one.panic("...")avoidNot for ordinary failures — return an error instead.
defer f.Close()★Guaranteed cleanup when the function returns.defer log(x)eval-nowArgs are evaluated now; the body runs at exit.defer a(); defer b()Deferred calls run in LIFO order (b then a).panic("boom")stopsUnwinds the stack, running defers as it goes.recover()Stops a panic — only meaningful inside a deferred func.defer func(){ recover() }()The catch pattern; convert a panic to an error.
[3]int{1, 2, 3}A fixed-size array (a value — copied on assign).[]int{1, 2, 3}★A slice: dynamic view over a backing array.make([]int, 0, 10)★Allocate:make([]T, len, cap).s = append(s, x)★reassignGrow — reassign, since it may reallocate.s[1:3]aliasesSub-slice[low:high)shares the backing array.len(s) cap(s)Length and capacity.copy(dst, src)Copy elements between slices.slices.Sort(s); slices.Contains(s, x)1.21The genericslicespackage.s[1:3:3]capThree-index slice capscap— stopsappendfrom clobbering the base.slices.Clone(s)★1.21Copy a slice (fresh backing array).slices.Insert(s, i, x); slices.Delete(s, i, j)1.21Insert/remove by index, generically.clear(s)1.21Zero every element in place.
m := map[string]int{"a": 1}★Map literal.make(map[string]int)Allocate an empty, writable map.m["b"] = 2★Insert or update.v := m["z"]Missing key returns the value's zero, not an error.v, ok := m["z"]★Comma-ok:oktells you if the key exists.delete(m, "a")Remove a key.for k, v := range mrandomIteration order is random by design.var m map[string]int; m["x"]=1nil-mapWriting to a nil map panics.set := map[string]struct{}{}setThe idiomatic set — a zero-width value.maps.Clone(m); maps.Equal(a, b)1.21Copy / compare maps generically.maps.Keys(m) maps.Values(m)1.23Iterators over a map.
type Point struct { X, Y int }★Declare a struct type.p := Point{X: 1, Y: 2}★Keyed literal (order-independent, safe).p := Point{1, 2}Positional literal (fragile if fields move).p.XField access (works through pointers too).&Point{1, 2}Pointer to a struct literal.type Big struct { Point; Name string }★Embedding: composition, not inheritance.Name string `json:"name"`Struct tags carry metadata (JSON, DB, ...).new(Point{1, 2})1.26newnow takes an expression →*Point.p := struct{ X, Y int }{1, 2}Anonymous struct — a one-off type, no declaration.a == bStructs compare with==if all fields are comparable.
func (p Point) Dist() float64★Value receiver — operates on a copy.func (p *Point) Move(dx int)★Pointer receiver — can mutate the value.p.Move(1)Go auto-takes&pwhen calling a*-method.value receiver can't mutateuse *TChanges to a value receiver are lost on return.func (m Celsius) F() CelsiusMethods attach to any named type, not just structs.f := p.DistMethod value: a bound closure you can pass around.g := Point.DistMethod expression: receiver becomes the first argument.only *T has pointer-receiver methodsmethod setA*Tsatisfies more interfaces than aT— the method-set rule.
type Stringer interface { String() string }★An interface = a set of method signatures.// no "implements" keyword★A type satisfies it just by having the methods.any = interface{}1.18The empty interface holds any value.v, ok := x.(int)★Type assertion, comma-ok form (never panics).switch v := x.(type) { case int: }★Type switch over the dynamic type.(type, value)An interface value is a type + a value pair.var e error = (*T)(nil); e != niltyped-nilA non-nil interface can hold a nil pointer.interface { io.Reader; io.Writer }Interfaces embed other interfaces (→io.ReadWriter).io.Reader, io.Writer, fmt.StringerstdlibThe small stdlib interfaces everything speaks.accept interfaces, return structsdesignA common design guideline.
func Map[T, U any](s []T, f func(T) U) []U★1.18Type parameters in square brackets.[T any]Theanyconstraint accepts every type.[T comparable]★Types usable with==/ map keys.type Number interface { ~int | ~float64 }A constraint = a set of allowed types.~intApproximation: any type whose underlying type isint.Map(xs, f)Type args are usually inferred — omit[int, string].[T cmp.Ordered]1.21The stdlib constraint for< >-comparable types.type Set[T comparable] = map[T]bool1.24Generic type aliases.type Adder[A Adder[A]] interface { Add(A) A }1.26Self-referential constraints now allowed.
go f(x)★Start a concurrent goroutine — cheap (a few KB).ch := make(chan int)★An unbuffered channel (a rendezvous).ch <- v★Send — blocks until someone receives.v := <-ch★Receive — blocks until someone sends.make(chan int, 8)Buffered — blocks only when full/empty.close(ch)Signal “no more sends”; receivers drain, then get zero.v, ok := <-chokis false once closed and drained.func send(ch chan<- int) func recv(ch <-chan int)Directional channels document & enforce intent.for v := range ch★Receive until the channel is closed.ch <- v // on a closed chpanicSending on a closed channel panics.
select { case <-a: ; case b <- x: }★Wait on the first ready channel.select { default: }Adefaultmakes it non-blocking.mu.Lock(); defer mu.Unlock()★Guard shared state with async.Mutex.wg.Add(1); ...; wg.Wait()★Wait for a set of goroutines to finish.wg.Go(func(){ ... })1.25Spawn + count in one call.var mu sync.RWMutex; mu.RLock()Many readers or one writer — cheaper for read-heavy state.var n atomic.Int64; n.Add(1)★Lock-free counters & flags viasync/atomic.sync.Once{}.Do(f)Run something exactly once.ctx, cancel := context.WithCancel(context.Background())Manual cancellation of a goroutine tree.ctx, cancel := context.WithTimeout(...)★Deadlines & cancellation; alwaysdefer cancel().<-ctx.Done()React when the context is cancelled.go test -raceraceCatch data races — use it.
go.mod★Module path + go version + requirements.module example.com/appThe import-path root of your module.go 1.25The language-version line.import "example.com/app/store"Import by full path; the last element is the name.go get pkg@v1.4.0Pin an exact version.go mod tidy★Add missing & drop unused dependencies.go mod downloadPopulate the module cache.go.sumChecksums for reproducible builds — commit it.internal/internalPackages importable only within the parent tree.replace example.com/x => ../xPoint a dependency at a local/fork path (dev).go.work1.18Workspace file spanning several local modules.tool example.com/cmd/x1.24Track build tools in go.mod.
foo_test.goTest files live beside the code they test.func TestX(t *testing.T)★A test; fail witht.Errorf/t.Fatal.go test ./...Run the whole suite.t.Run("case", func(t *testing.T){})★Table-driven subtests.if got != want { t.Errorf(...) }Report a mismatch and continue.func BenchmarkX(b *testing.B){ for b.Loop() {} }1.24Modern benchmark loop.func ExampleX() { ... }Runnable doc examples — checked against// Output:.synctest.Test(t, func(t *testing.T){})1.25Deterministic concurrency tests (virtual clock).func FuzzX(f *testing.F){ f.Fuzz(func(t, s string){}) }★1.18Native fuzzing — run with-fuzz=.t.Parallel()Mark a test to run alongside other parallel tests.t.Cleanup(func(){ ... })Register teardown (runs even ont.Fatal).go test -race -coverRace detector & coverage.