You have this code:
```go
func do() error {
var p *MyError // MyError implements error
if false {
p = &MyError{}
}
return p
}
func main() {
if err := do(); err != nil {
fmt.Println("got error")
} else {
fmt.Println("no error")
}
}
```
What prints, and why?
- A. "no error", because a nil *MyError returned as error is a nil interface
- B. "got error", because the returned interface holds a non-nil type descriptor even though its value pointer is nil ✓
- C. A compile error, because you cannot return a typed nil as an error interface
- D. A panic at runtime when err is compared to nil
Correct answer: B. An interface is a (type, value) pair; assigning a typed nil *MyError makes the type word non-nil, so the interface != nil even though the underlying pointer is nil.
In Go 1.21 (before the 1.22 loop-variable change), this runs:
```go
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func() { defer wg.Done(); fmt.Print(i) }()
}
wg.Wait()
```
What is the most accurate statement about its output?
- A. It always prints exactly "012" in order
- B. It reliably prints "333" every run
- C. It commonly prints "333" but the exact digits are unspecified because all goroutines share one i whose final value is 3 and scheduling is nondeterministic ✓
- D. It is a compile error because i is captured by reference
Correct answer: C. Pre-1.22 all closures capture the same i, which reaches 3 after the loop; output is nondeterministic but typically "333" since goroutines usually run after the loop completes.
Consider:
```go
a := []int{1, 2, 3, 4}
b := a[:2]
b = append(b, 99)
fmt.Println(a)
```
What does this print?
- A. [1 2 3 4]
- B. [1 2 99 4] ✓
- C. [1 2 99]
- D. [1 2 3 4 99]
Correct answer: B. b shares a's backing array with len 2 but cap 4, so append writes 99 into index 2 in place, overwriting the original 3.
A service shows steadily rising memory and `runtime.NumGoroutine()` climbing without bound. The suspect code:
```go
func fetch(ctx context.Context) int {
ch := make(chan int)
go func() { ch <- expensive() }()
select {
case v := <-ch:
return v
case <-ctx.Done():
return -1
}
}
```
What is the leak and the minimal fix?
- A. No leak; the goroutine is garbage collected once fetch returns
- B. On ctx cancellation the goroutine blocks forever on the unbuffered send; make ch buffered with capacity 1 so the send always completes ✓
- C. The leak is expensive() being slow; wrap it in a timeout instead
- D. Add defer close(ch) in fetch so the goroutine's send unblocks
Correct answer: B. When ctx.Done fires first, no one ever receives from the unbuffered ch, so the sender blocks permanently; a capacity-1 buffer lets the send complete and the goroutine exit.
Which statement about a nil pointer receiver is correct?
```go
type T struct{ v int }
func (t *T) Ping() string { return "pong" }
func (t *T) Val() int { return t.v }
```
- A. Calling Ping on a nil *T panics because the receiver is nil
- B. Calling Ping on a nil *T works, but calling Val on a nil *T panics when it dereferences t.v ✓
- C. Both Ping and Val panic on a nil *T
- D. Neither panics; t.v on a nil receiver returns the zero value safely
Correct answer: B. A method call on a nil pointer receiver is legal; it only panics if the body dereferences the pointer, so Ping is safe but Val's access to t.v faults.
Two goroutines run concurrently with no synchronization:
```go
m := map[int]int{}
go func() { for i := 0; i < 1000; i++ { m[i] = i } }()
go func() { for i := 0; i < 1000; i++ { m[i] = -i } }()
```
What is the defined behavior?
- A. The map ends up with some interleaved mix of values but never crashes
- B. The Go runtime may detect concurrent map writes and deliberately panic with "concurrent map writes" ✓
- C. It always produces a data-race compile error without -race
- D. Writes are serialized internally by a built-in map lock, so it is safe
Correct answer: B. Go maps are not concurrency-safe and the runtime intentionally detects concurrent access, calling fatal("concurrent map writes") to fail loudly rather than corrupt silently.
What does this print?
```go
func f() (result int) {
defer func() { result *= 2 }()
result = 5
return 10
}
fmt.Println(f())
```
Correct answer: B. return 10 sets the named return value result to 10, then the deferred closure runs and doubles it to 20 before the function actually returns.
You need a cache read heavily, written rarely, with keys of one type, from many goroutines. For lowest overhead in the read-dominated steady state, which choice is best and why?
- A. sync.Map, because it is always faster than a mutex-guarded map
- B. A plain map guarded by sync.Mutex, because mutexes are cheaper than atomics
- C. A plain map guarded by sync.RWMutex, allowing concurrent readers while still serializing the rare writes ✓
- D. An unsynchronized map, since rare writes make races unlikely
Correct answer: C. An RWMutex lets many readers proceed in parallel and only blocks for the infrequent writes, which fits a read-heavy homogeneous-key workload better than the interface-boxing and dual-store overhead of sync.Map.
Regarding escape analysis, which scenario forces the value to be heap-allocated?
```go
// A
func a() int { x := 42; return x }
// B
func b() *int { x := 42; return &x }
// C
func c() { x := 42; _ = x }
```
- A. A, because returning a value copies it to the heap
- B. B, because the address of x outlives the stack frame so it must escape to the heap ✓
- C. C, because unused locals are heap-allocated
- D. None; Go always stack-allocates locals declared with :=
Correct answer: B. Returning &x means the pointer outlives b's frame, so escape analysis moves x to the heap; a and c keep x on the stack.
In a select with multiple ready cases:
```go
select {
case <-a:
// ...
case <-b:
// ...
default:
// ...
}
```
Which statement is precisely correct?
- A. Cases are evaluated top-to-bottom, so a wins whenever both a and b are ready
- B. If both a and b are ready, one is chosen uniformly at random; default runs only when neither a nor b is ready ✓
- C. default is chosen whenever it is present, making the select non-blocking always
- D. The select blocks until all channels are ready
Correct answer: B. When several non-default cases are ready select picks one at pseudo-random (no priority), and the default clause only executes when no other case can proceed immediately.