Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

Part 4: Errors, Sync & Top Gotchas
GO

Part 4: Errors, Sync & Top Gotchas

Revise Go error handling, synchronization utilities, nil versus empty values, tooling, and common language gotchas.

1. Error handling — no exceptions

  • Functions return errors as a value; check them explicitly.
f, err := os.Open("x.txt")
if err != nil {
    log.Fatal(err)
}
  • errors.New("...") for simple errors; wrap with fmt.Errorf("...: %w", err) to preserve context.
  • errors.Is(err, target) / errors.As(err, &target) for sentinel errors and typed unwrapping.
  • Prefer an error type (struct implementing Error() string) when extra info is needed.

2. sync utilities

sync.Mutex

  • mu.Lock() / mu.Unlock() guard shared state.
  • Always defer mu.Unlock() right after locking.

sync.RWMutex

  • Multiple readers or one writer; RLock/RUnlock for reads, Lock/Unlock for writes.

sync.WaitGroup

  • wg.Add(1) / go worker(); wg.Done() / wg.Wait() — the classic “wait for goroutines” pattern.
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(n int) { defer wg.Done(); fmt.Println(n) }(i)
}
wg.Wait()

sync.Once

  • once.Do(f) runs f exactly once, even across goroutines — lazy init.

atomic

  • sync/atomic for lock-free counters: atomic.AddInt64(&n, 1).
  • atomic.Value for typed lock-free reads/writes.

3. nil vs empty — the FAQ

Thingnilempty / zero
slicevar s []int → nil, len 0s := []int{} — non-nil, len 0
mapvar m map[string]int — read OK, write panicsm := map[...]...
stringempty string ""
  • len/cap/range on a nil slice/map is fine; only map writes panic.
  • nil slice == nil slice; []int{} == nil? No.
  • s == nil is the common presence check; len(s) == 0 is the “empty” check.

4. Gotcha sheet — interview fast-refresh

  • Slicing aliases the backing array.
  • Ranges copyfor i, v := range slice copies v.
  • Closure capture: for i := range xs { go func(){ fmt.Println(i) }() } — with Go < 1.22 all print the last value; the variables are per-loop now but the rule of capturing a copy still applies.
  • Defer args are evaluated at defer time.
  • Struct field tags don’t affect equality.
  • byte = uint8, rune = int32 — aliases.
  • Zero value used as default — structs start zeroed, no constructor needed.
  • Interface holds type + value — the “typed nil” trap.

5. Interview checkpoint

  • Error vs panic balance; errors.Is/As.
  • Mutex/WaitGroup/atomic when questions get concurrency-y.
  • nil vs empty slice/map — the interview favorite.
  • Shadowing (:= vs =) and unused variable errors.
  • go vet, go test, go fmt, go mod tidy — the daily cadence.

My Private Notes

Notes are auto-saved locally to this device.