Go Interview Questions
Q: What makes Go different from other languages?
Go's key differentiators: (1) Built-in concurrency with goroutines (cheap, ~2KB stack) and channels. (2) Compiles to a single static binary — no runtime dependencies. (3) Fast compilation. (4) Explicit error handling (no exceptions). (5) Implicit interface satisfaction. (6) Garbage collected but with minimal pause. (7) Simplicity — deliberately small language spec.
Q: What is a goroutine and how does it differ from a thread?
Goroutines are lightweight, user-space threads managed by the Go runtime. They start with ~2KB stack (grows dynamically) vs OS threads (~1-8MB). The Go scheduler multiplexes many goroutines onto a few OS threads (M:N threading). Switching goroutines is much faster than OS context switches. You can run millions of goroutines concurrently.
Q: What is the difference between a channel and a mutex?
Channels are for communication and synchronization between goroutines — pass data via channels instead of sharing memory. Mutexes protect shared memory from concurrent access. Go's motto: "Don't communicate by sharing memory; share memory by communicating." Use channels for pipelines/worker patterns. Use mutexes when you have simple shared state (counters, caches).
Q: How does Go handle errors?
Go has no exceptions. Functions return an error as the last return value. Callers must explicitly check errors. This makes error handling visible and forces you to think about every failure path. Use fmt.Errorf("context: %w", err) to wrap errors with context. Use errors.Is() to check for specific error values and errors.As() to check for specific error types.
Q: What is a nil pointer dereference and how do you avoid it?
Accessing a field or method on a nil pointer causes a panic. Avoid by checking for nil before use: if user != nil { ... }. Return errors instead of nil values when operations fail. Use the "comma ok" pattern for map access and type assertions. Pointer receivers work on nil pointers if the method handles it explicitly.
Q: What is a slice vs array in Go?
An array has a fixed size ([3]int) and is a value type — copying it copies all elements. A slice is a dynamic view into an underlying array (pointer + length + capacity) and is a reference type — slices created from the same array share memory. Slices are almost always preferred over arrays in Go.
Q: What is defer and when is it used?
defer schedules a function call to run when the surrounding function returns (even if it panics). Deferred calls execute in LIFO (last-in, first-out) order. Primary use: resource cleanup — defer f.Close(), defer mu.Unlock(), defer wg.Done(). Arguments to deferred functions are evaluated immediately at the defer statement.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free