The Go language is often programmed by combining simple functions, and error checking occurs for each function, so the code in general tends to be long.
Even when I want to do something small, I need to write code accordingly, but it is tedious to write from scratch every time, so I would like to write down the processes I often do for my own copy and paste.
Here is my own note on how to read and write JSON in the Go language.
Structure element names are uppercase.
When working with JSON, we often convert from structure to JSON, from JSON to structure, or exchange through structures.
In the Go language, if the element name of a structure does not begin with an uppercase letter, the elements of that structure will not be exposed to other packages.
Therefore, when using the json
package to process JSON, the element names of the structure to be exchanged must begin with an uppercase letter.
However, JSON data does not necessarily mean that the element name starts with a capital letter.
So, while the element name of the structure should start with an uppercase letter, the tag of the structure should indicate which element name of JSON it represents.
type colStruct struct { Name string `json: "name"` Count int `json: "count"` }
JSON read (structure)
Prepare a structure to receive data, and pass JSON data and a pointer to the structure to json.Unmarshal()
to store the data in the structure.
data := `{"x":123, "y":"ABC"}` var a struct { X int `json:"x"` Y string `json:"y"` } err := json.Unmarshal([]byte(data), &a) if err != nil { return err } fmt.Printf("%+v\n", a) // {X:123 Y:ABC}
JSON read (interface)
If the contents of the JSON data are unknown, arbitrary JSON data can be retrieved at the interface by passing a pointer to the interface instead of a structure.
Use type assertions to retrieve data from the interface.
The retrieved data is also an interface, so to retrieve nested data, type assertions must be repeated.
data := `{"x":123, "y":"ABC", "z":{"i":123, "j":456}}` var a interface{} err := json.Unmarshal([]byte(data), &a) if err != nil { return err } fmt.Printf("%#v\n", a) // map[string]interface {}{"Z":map[string]interface {}{"a":123, "b":456}, "x":123, "y":"ABC"} b := a.(map[string]interface{})["z"] z := b.(map[string]interface{}) fmt.Println(z["i"]) // 123 fmt.Println(z["j"]) // ABC
JSON output (structure)
Pass the structure you want to output to json.Marshal()
and it will convert it to JSON.
a := struct { X int `json:"x"` Y string `json:"y"` }{ X: 123, Y: "ABC", } json, err := json.Marshal(a) if err != nil { return err } fmt.Printf("%+v\n", string(json)) // {"x":123,"y":"ABC"}
JSON output (slice map interface)
Since json.Marshal()
internally processes everything in the interface, not only structures, but also slices, maps, and interfaces are all mixed together,
It converts not only structures, but also data with a jumble of slices, maps, and interfaces into JSON.
z := struct { I int `json:"i"` J int `json:"j"` }{ I: 123, J: 456, } a := map[string]interface{}{ "x": 123, "y": "ABC", "z": z, } json, err := json.Marshal(a) if err != nil { return err } fmt.Printf("%+v\n", string(json)) // {"x":123,"y":"ABC","z":{"i":123,"j":456}}
stream processing
Since json
can read/write directly to io.Reader
and io.Writer
, there is no need to load data into memory once.
Stream JSON read
var a struct { X int `json:"x"` Y string `json:"y"` } f, err := os.Open("data_input.json") // {"x":123 "y":"ABC"} if err != nil { return err } defer f.Close() err = json.NewDecoder(f).Decode(&a) if err != nil { return err } fmt.Printf("%+v\n", a) // {X:123 Y:ABC}
Stream JSON output
a := map[string]interface{}{ "x": 123, "y": "ABC", } f, err := os.Create("data_output.json") if err != nil { return err } defer f.Close() err = json.NewEncoder(f).Encode(a) if err != nil { return err }
Impressions, etc.
I typed the article and reread it, but the code is not very readable because the error handling code interrupts my thinking.
Since the Go language does not have "exceptions", error handling becomes mandatory and cannot be omitted, so I hear that the Go language should also have "exceptions".
The Go language actually requires a semicolon at the end of a line, but even if you don't write it, the compiler will complete it for you.
As such, there are things in the Go language, such as compiler interpretation rather than language specification, that make the language easier to write and read.
So I don't have to introduce "exceptions" to the Go language.
When the compiler receives the return value of a function in the err
variable, it automatically inserts if err != nil { return err }
on the next line.
It would be nice to include a feature that would make coding easier, like