Use `json.Decoder` when JSON comes from an `io.Reader`, such as an open file. Create it with `json.NewDecoder(reader)`, then call `Decode` with a pointer to the Go value that should receive the data. Check the returned error before using that value. section 3.1.3 section 6.5.4
The destination must match the JSON shape. For a list of bookworms, use a `[]Bookworm`; give its struct fields `json` tags to map JSON names to Go names. Fields must be exported so the decoder can fill them. Passing `&bookworms` lets decoding update the variable rather than a copy. section 3.1.3
Listing 3.6 bookworm.go: loadBookworms() parses the JSON file
// loadBookworms reads the file and returns the list of bookworms,
// and their beloved books, found therein.
func loadBookworms(filePath string) ([]Bookworm, error) {
f, err := os.Open(filePath) #1
if err != nil {
return nil, err
}
defer f.Close() #2
// Initialize the type in which the file will be decoded.
var bookworms []Bookworm
// Decode the file and store the content in the variable bookworms.
err = json.NewDecoder(f).Decode(&bookworms) #3
if err != nil {
return nil, err
}
return bookworms, nil
}
A complete file-loading function opens and closes the file, decodes into a slice, and returns any decoding error. section 3.1.3
Choose the API by the input you already have: `json.Decoder` reads an `io.Reader`, while `json.Unmarshal` accepts a complete `[]byte`. A byte slice can also be wrapped in a reader for `NewDecoder`. The file-loading example does not demonstrate the more refined approach of explicitly streaming a large input. section 3.5 section 6.5.4 section 3.1.3
p := person{}dec := json.NewDecoder(bytes.NewReader(data)) // Or use an io.Readererr := dec.Decode(&p)if err != nil {panic(err)}
A byte slice wrapped with `bytes.NewReader` shows that `Decode` still takes a pointer, even when the original data is already in memory. section 6.5.4
