Go interviewer course · Reference 0001

Interviewer desk sheet

Intermediate Go
in 10 questions

Five struct/interface questions. Five concurrency questions. Four minutes each. Score prediction + model + safe fix.

0 · incorrect / unsafe 1 · result, weak reasoning 2 · result + model + fix

Opening script

“I’ll show short Go scenarios. First predict what happens and explain why; then suggest a safe design. It’s fine to think aloud. I care more about your model and trade-offs than exact terminology.”

3 minSet expectations
20 minStructs + interfaces
20 minConcurrency
7 minCandidate questions

Question bank

Ask → listen → probe

Structs & interfaces

#AskMust hear for 2 pointsProbe / red flag
1 c.Add(), Incrementer=c, Incrementer=&c: which compile when Add has a pointer receiver? Call / assignment / assignment = yes / no / yes. Addressable-call shorthand differs from method-set satisfaction. Probe: mutating receiver?
Red: “pointer methods work on both.”
2 Copy a struct containing a slice and map, then mutate elements through the copy. What changes in the original? Struct fields are copied, but slice backing storage and map data remain shared. Deep-copy referenced data for independence. Probe: append and capacity?
Red: “structs are references” or “always deep copied.”
3 C embeds A and B; both define Ping. Does C implement interface{ Ping() }? No: same-depth promotion is ambiguous. Qualify the field or declare C.Ping. Embedding is composition, not inheritance. Probe: add C.Ping?
Red: subclass/override language.
4 A function returns error containing (*AppError)(nil). Is the returned interface nil? No. It contains dynamic type *AppError and dynamic value nil. Return explicit nil on success. Probe: method call through it?
Red: reflection as the normal fix.
5 An encoder only writes bytes. Accept *bytes.Buffer, a broad custom interface, or io.Writer? io.Writer: smallest established consumer need. Don’t require or invoke lifecycle methods the function does not own. Probe: constructor return type?
Red: speculative methods or closing caller-owned writer.

Concurrency

#AskMust hear for 2 pointsProbe / red flag
6 A goroutine writes n=1; main immediately prints n. What happens? Data race; no guaranteed value. Starting a goroutine does not join it. Use a channel or WaitGroup to order completion. Probe: is sleep a fix?
Red: deterministic answer based on timing.
7 Same goroutine sends twice to capacity-one channel, then receives. What happens? Second send blocks; deadlock. Buffer decouples only up to capacity and then applies backpressure. Capacity two is brittle here. Probe: meaningful cap-one cases?
Red: “make buffer huge.”
8 Many workers send to one results channel. Who closes it, and when? Sender-side coordinator closes after wg.Wait, while consumer drains. Closed receive / send / nil semantics are clear. Probe: why coordinator goroutine?
Red: every worker closes output.
9 A value-receiver method locks a mutex field and writes a map field. Why unsafe? Receiver copies mutex while map storage remains shared. Use pointer receiver; never copy mutex after use; lock all accesses. Probe: RWMutex trade-off?
Red: focuses only on defer cost.
10 Producer sends forever; caller receives one value then returns. What remains? Producer leaks on a blocked send. Propagate context/done, select sends against cancellation, sender closes output. Probe: blocking inner call?
Red: buffer or GC as lifecycle control.

Full code, explanations, and interactive scoring: open the lesson.

Fast facts

The mental model at a glance

Types

  • T method set: methods on T.
  • *T method set: methods on T and *T.
  • Interface nil only when dynamic type and value are both absent.
  • Embedding promotes unambiguous selectors; it is not inheritance.
  • Struct assignment copies fields; reference-like fields may still alias.

Coordination

  • Channel: values, signals, ownership transfer, ordering.
  • Mutex: one shared invariant, one consistent lock rule.
  • WaitGroup: completion only.
  • Context: cancellation/deadline through an operation tree.
  • Goroutine: must have a stop condition and observable completion when needed.

Closed channel

Receive drains buffered values, then returns zero value and ok=false. Send panics. Closing again panics.

Nil channel

Send and receive block forever. In select, a nil-channel case is disabled.

Race check

go test -race ./... detects races only on runtime paths actually exercised.

Close well

Before deciding

  • Separate missing terminology from missing reasoning.
  • Accept an alternative design when ownership, lifetime, and synchronization are sound.
  • Record one concrete example supporting every strong or weak rating.
  • Do not convert the 20-point total into an automatic hiring decision.