GO / CHAPTER 10

Readers, records, and partial progress

Advanced

Separate successfully read data from end-of-input and other failures.

By the end of this chapter

  • Handle data before a terminal read error
  • Check scanner errors after iteration
  • Define malformed-record behavior

The idea

The io.Reader interface reports both a byte count and an error. A call may return useful bytes together with a terminal error, so process the first n bytes before handling that error. Only the returned prefix belongs to the current read. Buffer capacity does not tell you how much fresh data arrived, and a later read may overwrite the same storage.

bufio.Scanner offers convenient token iteration, including line scanning by default. After its loop ends, check Err to distinguish ordinary completion from a scanning failure. Scanner also has a token-size limit unless configured differently. At the record layer, decide whether malformed input stops the operation or is collected as a separate failure; silently treating bad data as zero loses important information.

Go example
package main
import ("fmt"; "bufio"; "strings")
func main(){ s:=bufio.NewScanner(strings.NewReader("red

blue
")); n:=0; for s.Scan(){ if s.Text()!="" {n++} }; if err:=s.Err(); err!=nil {panic(err)}; fmt.Println(n) }
Result
2

Three lines are scanned; the explicit empty-line policy counts only red and blue, and scanner failure is checked afterward.

Try it yourself

Parse one integer per line and return a useful line-numbered error for malformed input.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

A read returns n=3 and io.EOF. What should the consumer do?