What is the exact io.Reader contract? What's wrong with this read loop?
for {
n, err := r.Read(buf)
if err != nil {
break
}
process(buf[:n])
}
The contract: Read may return n > 0 and a non-nil error in the same call (including io.EOF). Callers must process the n bytes before considering the error. The loop above drops the final chunk from readers that return data together with EOF. Also, Read may return fewer bytes than len(buf) even when more data is coming — it doesn't fill the buffer; use io.ReadFull when you need exactly N bytes. Returning 0, nil is discouraged but legal (treat as "nothing happened").
for {
n, err := r.Read(buf)
if n > 0 {
process(buf[:n])
}
if err == io.EOF {
break
}
if err != nil {
return err
}
}
Better: avoid hand-written loops — use io.Copy, io.ReadAll (bounded with io.LimitReader), bufio.Scanner or io.ReadFull. For io.Writer the contract is stricter: if n < len(p) it must return a non-nil error, and it must not retain p.
Interviewer looks for: "n before err", short reads, and io.EOF being a sentinel value (compare with == or errors.Is).
More on Standard Library, HTTP & Systems Design in Go
- Q456How does database/sql connection pooling work? Which settings matter and what causes connection leaks?
- Q457How do you handle transactions, NULLs and "no rows" correctly with database/sql?
- Q459Compose io primitives: upload a file to HTTP while computing its SHA-256 and limiting size, without buffering it in memory.
- Q460What are the pitfalls of bufio.Scanner and bufio.Writer?
- Q461Implement graceful shutdown for an HTTP server with background workers.
- Q462How does log/slog work? Discuss handlers, attributes, LogValuer, and performance.