Deserialization, also called unmarshaling, turns serialized data into in-memory values. In Go, a practical starting point is a configuration file: define a struct that matches the data, decode into it at startup, and check the returned error before using its fields. section 2.2.1
Listing 2.9 Parsing a JSON configuration file: json_config.go
package main
import (
"encoding/json"
"fmt"
"os"
)
type configuration struct { #1
Enabled bool #1
Path string #1
} #1
func main() {
file, err := os.Open("config.json") #2
if err != nil {
panic(err)
}
defer file.Close()
decoder := json.NewDecoder(file) #3
conf := configuration{} #3
err = decoder.Decode(&conf) #3
if err != nil {
fmt.Println("Error:", err)
}
fmt.Println(conf.Path)
}
A JSON configuration parser opens a file, passes it to json.NewDecoder, and calls Decode with a pointer to the destination struct. section 2.2.1
Fields that another package must populate need uppercase initial letters. Match the struct’s names and nesting to the JSON representation; otherwise, parts of the configuration may not be populated as intended. The decoded values are then available through the struct instance. section 2.2.1
Choose the decoding path to fit the format and workload:
- For a JSON configuration file, use the standard library’s encoding/json decoder and a matching struct. section 2.2.1
- For repeatedly decoded REST JSON, consider generated codec code. Unlike encoding/json’s reflection-based path, generated code avoids repeated type inspection and can reduce execution and allocation costs. section 12.3.1
- For a custom key-value format, write Unmarshal(data []byte, v interface{}) error and use reflection to connect input names to tagged struct fields. section 13.2.3
Listing 12.8 Decoding JSON into an instance of a type
var u2 user.User #1
err = codec.NewDecoderBytes(out, jh).Decode(&u2) #2
if err != nil {
…
}
fmt.Println(u2) #3
The codec decoder takes JSON bytes and a destination pointer, then populates a typed value. Its surrounding example uses a struct with codec tags and generated code. section 12.3.1
A custom INI-like decoder can scan the input line by line, split each valid line at its first equals sign, and pass the name and value to a field-setting helper. The helper matches names against ini tags and converts supported field types. This example is deliberately limited to structs and skips malformed lines; it is a pattern to adapt, not a general-purpose format parser. section 13.2.3
Listing 13.15 The Unmarshal function
func Unmarshal(data []byte, v interface{}) error {
val := reflect.Indirect(reflect.ValueOf(v)) #1
t := val.Type()
b := bytes.NewBuffer(data)
scanner := bufio.NewScanner(b) #2
for scanner.Scan() { #2
line := scanner.Text() #2
pair := strings.SplitN(line, "=", 2) #3
if len(pair) < 2 {
// Skip any malformed lines.
continue
}
setField(pair[0], pair[1], t, val) #4
}
return nil
}
The Unmarshal implementation shows the scanner, first-equals-sign split, and handoff to setField. section 13.2.3
Round-trip a tagged struct
A Processes struct uses ini tags such as `ini:"total"` and `ini:"load"`. Marshal produces key-value lines; Unmarshal reads those bytes into a new Processes value, demonstrating that the field mapping works in both directions. section 13.2.3









