Golang Coding Interview Tips: Idioms, Gotchas, and Snippets

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:

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:

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

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

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

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

Go rewards plain, readable code, and so do most interviewers.