Go (Golang) Interview Questions (60+ Deep Dive Q&A)
1. Core Architecture (GMP & Runtime)
1. GMP Scheduler Model (Visualized)
1. GMP Scheduler Model (Visualized)
- G (Goroutine): Stack (2KB). State.
- M (Machine): OS Thread. Executes instructions.
- P (Processor): Resource/Context required to run Go code. Has a Local Run Queue of Gs. Diagram:
2. Goroutine vs OS Thread
2. Goroutine vs OS Thread
| Feature | Goroutine | OS Thread |
|---|---|---|
| Size | ~2KB (Growable) | ~1-2MB (Fixed) |
| Creation | Cheap (User space) | Expensive (Kernel call) |
| Switching | Fast (Registers only) | Slow (Context switch) |
| Scheduler | Go Runtime | OS Kernel |
3. Garbage Collection (Tricolor Mark & Sweep)
3. Garbage Collection (Tricolor Mark & Sweep)
- Mark: Starts from Roots (Globals, Stacks).
- White: Unreachable.
- Grey: Reachable, children not scanned.
- Black: Reachable, children scanned.
- Write Barrier: Ensures no “Black” object points to “White” object during concurrent run.
- Sweep: Reclaim White objects. Goal: Low Latency (Stop The World < 500 microseconds).
4. Stack Growth (Contiguous vs Split)
4. Stack Growth (Contiguous vs Split)
5. Panic vs Error
5. Panic vs Error
- Error: Expected failure (File not found). Values returned as last argument. Checked explicitly.
- Panic: Unexpected failure (Index out of range, Nil pointer). Aborts execution.
- Recover:
recover()insidedefercatches panic and resumes normal flow.
6. `defer` Internals
6. `defer` Internals
defer had overhead in Go 1.13, but in 1.14+ (Open Coded Defer) it is nearly zero-cost (inlined).7. Map Internals
7. Map Internals
- Bucket: Array of 8 top-hash bits. Array of 8 Keys. Array of 8 Values. Overflow pointer.
- Load Factor: 6.5.
- Evacuation: When growing, buckets are incrementally moved to new array (gradual resize).
8. Slice vs Array
8. Slice vs Array
- Array: Value type. Fixed length.
[5]int. Copying array copies all elements. - Slice: Reference type (Header). Dynamic.
[]int.- Struct:
{ ptr *array, len int, cap int }. - Passing slice to function copies the struct (cheap), but ptr points to same data.
- Struct:
9. Context Package (`context`)
9. Context Package (`context`)
WithCancel(): Returns a function to cancel children.WithTimeout(): Cancels after time.WithValue(): Request-scoped data (Trace ID). Don’t abuse.
10. Pointers (Stack vs Heap Allocation)
10. Pointers (Stack vs Heap Allocation)
return &x (escapes) -> Heap (GC pressure).
go build -gcflags="-m" shows escape analysis.2. Concurrency Primitives (Channels)
11. Unbuffered vs Buffered Channels
11. Unbuffered vs Buffered Channels
- Unbuffered:
make(chan int). Synchronous. Sender blocks until Receiver deals. Receiver blocks until Sender sends. “Rendezvous”. - Buffered:
make(chan int, 5). Asynchronous. Sender blocks only if buffer full. Receiver blocks only if buffer empty.
12. `select` Statement
12. `select` Statement
switch but for channels.
Blocks until one case is ready.
If multiple ready, picks randomly (Pseudo-random).
Timeout Pattern:13. Nil Channel behavior
13. Nil Channel behavior
- Send to nil: Blocks Forever.
- Receive from nil: Blocks Forever.
- Close nil: Panic.
Use: Disable a
selectcase dynamically by setting channel var to nil.
14. Closing Channels
14. Closing Channels
val, ok := <-ch. If closed, ok is false, val is zero-value.
Sending to closed chan: Panic.
Closing already closed: Panic.15. Worker Pool Pattern
15. Worker Pool Pattern
- Jobs Channel: Buffered.
- Workers: Loop
range jobs. - WaitGroup: Wait for workers to finish.
16. `sync.WaitGroup`
16. `sync.WaitGroup`
Add(1), Done(), Wait().
Trap: Must pass pointer *sync.WaitGroup to functions, or it gets copied (deadlock).17. `sync.Mutex` vs `RWMutex`
17. `sync.Mutex` vs `RWMutex`
- Mutex:
Lock()blocks everyone. - RWMutex:
RLock()(Read Lock) allows multiple readers.Lock()(Write Lock) blocks readers and writers. Use RWMutex if Reads >> Writes (90/10 ratio).
18. `sync.Once`
18. `sync.Once`
19. `atomic` Package
19. `atomic` Package
AddInt64, CompareAndSwap).
Faster than Mutex but harder to get right.
Safe for simple counters.20. Race Detector
20. Race Detector
go run -race app.go.
Compiles with instrumentation to detect data races at runtime.
Performance hit (10x slow). Run in CI/Tests.3. Interfaces & Design
21. Implicit Interface Implementation
21. Implicit Interface Implementation
implements Interface.
If Type has methods Read() and Write(), it implements io.ReadWriter automatically.
Decouples implementation from abstraction.22. Empty Interface `interface{}` (any)
22. Empty Interface `interface{}` (any)
eface { _type, data }._type: Pointer to type metadata.data: Pointer to value. Use:fmt.Println, JSON marshalling.
23. Type Assertion vs Type Switch
23. Type Assertion vs Type Switch
- Assertion:
s, ok := val.(string). Check specific type. - Switch:
24. Interface Nil vs Value Nil
24. Interface Nil vs Value Nil
25. Embedding (Composition)
25. Embedding (Composition)
Child IS NOT Base. It HAS Base.26. Functional Options Pattern
26. Functional Options Pattern
27. Meaning of `make` vs `new`
27. Meaning of `make` vs `new`
new(T): Allocates memory (zeroed). Returns*T. Used for Structs, Ints.make(T): Initializes internal structure. ReturnsT. Used for Slices, Maps, Channels.
28. Standard Lib packages to know
28. Standard Lib packages to know
net/http: Robust server/client.encoding/json: Marshalling.io,bufio: Readers/Writers.sync: Primitives.time: Durations, Tickers.
29. Error Handling Best Practices
29. Error Handling Best Practices
- Check errors immediately.
- Wrap errors:
fmt.Errorf("reading file: %w", err). - Use
errors.Is(check type) anderrors.As(unwrap). - Don’t panic.
30. Go Modules (`go.mod`)
30. Go Modules (`go.mod`)
v1.2.3).
go.sum: Checksum database for security.
replace directive: Local development override.4. Coding Scenarios & Snippets
31. Fan-In Pattern
31. Fan-In Pattern
32. Pipeline Pattern
32. Pipeline Pattern
33. Graceful Shutdown
33. Graceful Shutdown
34. Reverse String (Rune aware)
34. Reverse String (Rune aware)
rune.35. Check Map key existence
35. Check Map key existence
36. Singleton (Thread Safe)
36. Singleton (Thread Safe)
37. Rate Limiter (Token Bucket)
37. Rate Limiter (Token Bucket)
time.Ticker.38. HTTP Middleware
38. HTTP Middleware
39. Testing (Table Driven)
39. Testing (Table Driven)
40. JSON Custom Marshal
40. JSON Custom Marshal
5. Edge Cases & Trivia
41. `range` loop variable trap
41. `range` loop variable trap
v is reused. Taking &v yields same pointer.v := v (shadowing) inside loop.42. Slice Capacity leak
42. Slice Capacity leak
huge[:2] keeps the underlying array in memory.
GC cannot collect the huge array.
Fix: copy small data to new slice.43. `init()` function
43. `init()` function
main().
Order: Imports -> Consts -> Vars -> Init.
Avoid side effects (DB connections) in init. Hard to test.44. Stack vs Heap (size)
44. Stack vs Heap (size)
45. Why no Generics (until 1.18)?
45. Why no Generics (until 1.18)?
46. `struct{}` (Empty Struct)
46. `struct{}` (Empty Struct)
map[string]struct{}: Set (Hashset). Save memory vs bool (1 byte).chan struct{}: Signal only.
47. Method Receiver (Value vs Pointer)
47. Method Receiver (Value vs Pointer)
(s MyStruct): Copy. Immutable (changes lost).(s *MyStruct): Pointer. Mutable. Rule: If you need to mutate, OR structure is large (> measureable bytes), uses pointer.
48. Can you recover from `fatal error: all goroutines are asleep - deadlock`?
48. Can you recover from `fatal error: all goroutines are asleep - deadlock`?
49. Internal ABI (Application Binary Interface)
49. Internal ABI (Application Binary Interface)
50. Reflect Package performance
50. Reflect Package performance
json, fmt.
Bypasses type safety.6. Advanced Go 1.22+ Features
51. Loop Variable Fix
51. Loop Variable Fix
for i := range create a NEW variable per iteration.
Removes common closure bug.52. `Creating Slices` efficient
52. `Creating Slices` efficient
slices package (1.21).
slices.Sort(), slices.Contains().
Written with Generics.53. Range over Integers
53. Range over Integers
for i := range 10 { ... }. (0 to 9).54. `http.ServeMux` enhancements
54. `http.ServeMux` enhancements
mux.HandleFunc("POST /items/{id}", ...)
Less need for Chi or Gorilla.55. Arena (Experiment)
55. Arena (Experiment)
56. `sync.Map`
56. `sync.Map`
- Write Once, Read Many (Cache).
- Disjoint keys (CPUs working on diff keys).
Generic
Mapcauses cache contention on the Lock/Buckets.sync.Mapreduces this.
57. Profile-Guided Optimization (PGO)
57. Profile-Guided Optimization (PGO)
default.pgo).
Compiler inlines hot functions better. ~2-7% speedup.58. Finalizers (`SetFinalizer`)
58. Finalizers (`SetFinalizer`)
defer.59. `unsafe` package
59. `unsafe` package
unsafe.Pointer (void*).
Use: Serialization, Syscalls, Hacking private fields (Don’t do it).60. Go Assembly
60. Go Assembly