GO / CHAPTER 10
Readers, records, and partial progress
AdvancedSeparate 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.
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) }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