Golang Coding Interview Tips: Idioms, Gotchas, and Snippets
Go works well in coding interviews: the syntax is small, the standard library is predictable, and the code is easy for an interviewer to read. It also has a few traps that cost time on a live pad. There's no built-in set, slices can share memory, the heap API needs boilerplate, and strings are bytes rather than characters.
These Golang coding interview tips cover the idioms worth having on autopilot, the bugs that show up most in timed rounds, and a short snippet sheet to review before you start. The examples assume Go 1.21 or later (for the built-in min/max and the slices package). If your interview environment might run an older version, ask, or fall back to sort and hand-written helpers.
Say your Go choices out loud
Interviewers who don't write Go every day may not know its idioms. A quick sentence helps:
"Go has no set type, so I'll use
map[int]struct{}. The empty struct takes no space."
"I'll copy this slice before appending to the result, because otherwise later appends can overwrite the shared backing array."
That turns a language detail into a sign that you understand the tool.
Maps: sets, counting, and the zero value
Reading a missing key returns the zero value, which makes counting very short:
counts := make(map[string]int)
for _, w := range words {
counts[w]++
}
For membership, use the two-value form when the zero value is a valid stored value:
seen := make(map[int]struct{})
seen[x] = struct{}{}
if _, ok := seen[y]; ok {
// y is in the set
}
Gotchas:
- Writing to a
nilmap panics.var m map[string]intfollowed bym["a"] = 1crashes, so initialize it withmake. - Map iteration order is randomized. If the output order matters, collect the keys and sort them.
Slices: append, aliasing, and copies
append may or may not allocate a new backing array. Two slices can silently share memory:
a := make([]int, 3, 10)
b := append(a, 4) // shares a's backing array (capacity 10)
c := append(a, 5) // writes to the same slot
fmt.Println(b[3], c[3]) // 5 5
This matters most in backtracking, where you append the current path to the results:
var res [][]int
var path []int
var dfs func(start int)
dfs = func(start int) {
res = append(res, append([]int(nil), path...)) // copy!
for i := start; i < len(nums); i++ {
path = append(path, nums[i])
dfs(i + 1)
path = path[:len(path)-1]
}
}
dfs(0)
Without the copy, the entries in res can change as path changes. Also note the two-step var dfs func(...) then dfs = func.... A closure can't call itself recursively if you declare it with := in one step.
Other slice habits:
- Pre-size when you know the length:
make([]int, n)ormake([]int, 0, n). - 2D grid: allocate each row;
make([][]int, m)alone gives you nil rows. - Stack:
stack = append(stack, x), thentop := stack[len(stack)-1]; stack = stack[:len(stack)-1]. - Queue:
q = q[1:]is fine for interview-sized BFS. You can mention that a ring buffer or an index pointer avoids holding onto memory.
Sorting
import (
"slices"
"sort"
)
slices.Sort(nums) // Go 1.21+
sort.Slice(intervals, func(i, j int) bool {
return intervals[i][0] < intervals[j][0]
})
sort.Slice isn't stable. Use sort.SliceStable if equal elements must keep their original order. The comparison must be a strict "less than": returning <= breaks the contract.
Heaps with container/heap
There's no ready-made priority queue. You implement five methods and then use the package functions:
import "container/heap"
type MinHeap []int
func (h MinHeap) Len() int { return len(h) }
func (h MinHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h MinHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *MinHeap) Push(x any) { *h = append(*h, x.(int)) }
func (h *MinHeap) Pop() any {
old := *h
n := len(old)
x := old[n-1]
*h = old[:n-1]
return x
}
h := &MinHeap{5, 2, 8}
heap.Init(h)
heap.Push(h, 1)
smallest := heap.Pop(h).(int) // 1
Common bugs: calling h.Push instead of heap.Push(h, ...) (that skips the heap fix-up), and forgetting that Pop on your type removes the last element, because heap.Pop swaps the minimum to the end first. For a max-heap, flip Less to >.
Practice typing this from memory until it takes under two minutes.
Strings, bytes, and runes
s[i]is a byte, not a character.for i, r := range syields runes (Unicode code points), andiis a byte offset.- Strings are immutable. To modify one, convert it:
b := []byte(s)for ASCII, or[]rune(s)for Unicode. - Build strings with
strings.Builderrather than repeated+=in a loop.
var sb strings.Builder
for _, w := range parts {
sb.WriteString(w)
}
out := sb.String()
For "lowercase letters only" problems, a [26]int array indexed by c - 'a' is fast, and arrays are comparable, so you can use them as map keys when grouping anagrams.
Integers and math
intis 64-bit on common 64-bit platforms. Say so if overflow could matter.minandmaxare built-in from Go 1.21; on older versions, write small helpers.- There's no integer
absin the standard library. Write one. - Integer division truncates toward zero, so
-7 / 2is-3. - For infinity, use
math.MaxIntormath.Inf(1)for floats.
Structs and multiple returns
Multiple return values make recursive helpers clean:
func dfs(node *TreeNode) (height int, balanced bool) {
if node == nil {
return 0, true
}
lh, lb := dfs(node.Left)
rh, rb := dfs(node.Right)
diff := lh - rh
if diff < 0 {
diff = -diff
}
return 1 + max(lh, rh), lb && rb && diff <= 1
}
A quick snippet sheet to review before the round
- [ ]
make(map[K]V)andmap[K]struct{}as a set - [ ] Two-value lookup:
v, ok := m[k] - [ ] Copy before storing:
append([]int(nil), path...) - [ ] Recursive closure:
var f func(...), thenf = func... - [ ]
sort.Slicewith a strict less,slices.Sorton Go 1.21+ - [ ]
container/heapfive methods plusheap.Init/Push/Pop - [ ]
strings.Builder,[]byte(s), runes fromrange - [ ] Grid rows allocated one by one
Soft practice note
Go idioms stick when you type them under a little pressure and explain them as you go. If you want timed, out-loud practice sessions to get Go snippets onto autopilot before a live round, Luna Interview is built for that kind of calm, structured prep. It's a practice tool, used before the interview.
Day-of checklist
- [ ] Confirm the Go version, or avoid 1.21-only features
- [ ] Heap boilerplate typed from memory at least once this week
- [ ] Copy-on-append habit in backtracking
- [ ] Explain one Go idiom out loud when you use it
- [ ] Dry run with an empty slice and a nil map in mind
Go rewards plain, readable code, and so do most interviewers.
Rehearse with an AI interview copilot, then browse commonly reported interview questions.