Exercises
Six Go drills that exercise the standard library idioms.
Six Go exercises
EXAMPLE
// ============================================================
// Drill 1 — Read a file safely
// ============================================================
// TASK: read /etc/hostname, return the hostname (trimmed).
//
// ANSWER:
func hostname() (string, error) {
b, err := os.ReadFile("/etc/hostname")
if err != nil { return "", fmt.Errorf("read hostname: %w", err) }
return strings.TrimSpace(string(b)), nil
}
// ============================================================
// Drill 2 — Walk a directory tree
// ============================================================
// TASK: find all .go files under ./src
//
// ANSWER:
func goFiles(root string) ([]string, error) {
var out []string
err := filepath.WalkDir(root, func(p string, d fs.DirEntry, err error) error {
if err != nil { return err }
if d.IsDir() || filepath.Ext(p) != ".go" { return nil }
out = append(out, p)
return nil
})
return out, err
}
// ============================================================
// Drill 3 — Concurrent HTTP fetches with a bounded pool
// ============================================================
// TASK: fetch N URLs with max 8 in flight.
//
// ANSWER:
func fetchAll(ctx context.Context, urls []string, concurrency int) []error {
sem := make(chan struct{}, concurrency)
errs := make([]error, len(urls))
var wg sync.WaitGroup
for i, u := range urls {
wg.Add(1)
sem <- struct{}{}
go func(i int, u string) {
defer wg.Done()
defer func() { <-sem }()
req, _ := http.NewRequestWithContext(ctx, "GET", u, nil)
res, err := http.DefaultClient.Do(req)
if err != nil { errs[i] = err; return }
res.Body.Close()
}(i, u)
}
wg.Wait()
return errs
}
// ============================================================
// Drill 4 — JSON streaming
// ============================================================
// TASK: read a giant array of objects without loading it all.
//
// ANSWER:
func streamJSON(r io.Reader) error {
dec := json.NewDecoder(r)
t, err := dec.Token() // expect [
if err != nil || t != json.Delim("[") { return fmt.Errorf("expected array") }
for dec.More() {
var item map[string]any
if err := dec.Decode(&item); err != nil { return err }
// process item ...
}
dec.Token() // closing ]
return nil
}
// ============================================================
// Drill 5 — Time-bound a slow operation
// ============================================================
// TASK: call an HTTP endpoint with a 2-second timeout.
//
// ANSWER:
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
res, err := http.DefaultClient.Do(req)
// err wraps context.DeadlineExceeded when the timeout fires
// ============================================================
// Drill 6 — Cancellable pipeline
// ============================================================
// TASK: a worker drains a channel of jobs; stops when ctx is cancelled.
//
// ANSWER:
func worker(ctx context.Context, jobs <-chan Job) {
for {
select {
case <-ctx.Done():
return
case j, ok := <-jobs:
if !ok { return }
process(j)
}
}
}
// ============================================================
// Bonus — atomic vs mutex for a counter
// ============================================================
// ANSWER: for an int counter use sync/atomic (lockless, faster). For
// multi-field state, use sync.Mutex / RWMutex.
// var n atomic.Int64
// n.Add(1); n.Load()
// ============================================================
// Scoring
// 6 / 6 -> production-ready Go
// 4 / 6 -> bookmark go/cheatsheet
// < 4 -> read the Go std lib examples on pkg.go.dev
type Job struct{}
func process(Job) {}
Why it matters
Always thread a `context.Context` through I/O and worker code. Cancellation, deadlines, and clean shutdowns are the difference between "the service stops when SIGTERM arrives" and "kubectl rollout takes 5 minutes because nothing honours the deadline".
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…