Step through small Go programs and watch what each line does to the stack and heap. Three scenarios: stack vs heap escape, slice growth, and map writes — the cases that confuse Python/JS engineers most.
Notes
Escape analysis: the compiler decides whether to allocate on the stack (cheap, freed at function return) or heap (managed by GC). Escape happens when the value's lifetime exceeds its enclosing function — most commonly when you return a pointer to a local, or store it in a field that outlives the function.
Slice growth: a slice is a header (pointer, len, cap). append within capacity reuses the backing array; exceeding capacity allocates a new (typically 2x larger) array and copies.
Struct copy: function parameters are copies by default. For small structs this is fine; for large structs it's why pointer receivers exist.