I tried various json behavior of go, so I will summarize it.
First of all, how to convert to json. The easiest way to do this is to do something like this:
import "encoding/json"
//...
jsonout, err := json.Marshal(Target object)
This method is easy to understand, but in reality, it is often converted in the following form.
encoder := json.NewEncoder(io where json is written.Writer)
err := encoder.Encode(Target object)
With the above method, any interface of io.Writer
can be used, so you can write to a file (os.File), write to an http response (http.ResponseWriter), or buffer (bufio.Writer). There is a high degree of freedom in writing to.
Now let's look at the output of the basic struct. The output content of json in the case of the following ordinary structure is as follows.
func main() {
type Sample struct {
IDString string
}
st := Sample{IDString: "xxfff"}
out, _ := json.Marshal(st)
fmt.Println(string(out)) // []Since it is a byte type, it is converted to a string
// Output:
// {"IDString":"xxfff"}
}
It is an image that the structure is converted to json as it is. It's intuitive. However, considering the naming convention of json, it is subtle whether it is said to be practical. Many people think that json's key name is lower camel and is often a snake case. To do this, you need to change the key name. To change the key name, use the tag character. The case where the key name is changed is as follows.
func main() {
type Sample struct {
IDString string `json:"id_string"`
}
st := Sample{IDString: "xxfff"}
out, _ := json.Marshal(st)
fmt.Println(string(out)) // []Since it is a byte type, it is converted to a string
// Output:
// {"id_string":"xxfff"}
}
Many people find it troublesome to insert tag characters one by one. However, there are no nice options in the official json library, so everyone is doing their best by using Tools.
The format of the json tag is as follows.
`(...) json:"[<key>][,<flag1>[,<flag2>]]" (...)`
As mentioned above, there are some json tags that can be specified other than changing the key name. The items that can be specified are as follows.
--Key name
As the name implies, this item is a json key name field. As will be described later, this is the highest priority among the key name specifications. If you specify -
, that field will be skipped. If you write nothing and only ,
, the name of the field of the structure is used as usual.
omitempty
If this item is specified, the value will be skipped when the value is zero. In the case of go language, the initial value is treated as zero value, so I think that this item is not used for types other than pointer type. The image is as follows.
func main() {
type Sample struct {
ID string `json:",omitempty"`
Pointer *string `json:",omitempty"`
}
s := Sample{ID: "", Pointer: nil}
out, _ := json.Marshal(s)
fmt.Println(string(out)) // []Since it is a byte type, it is converted to a string
// Output:
// {}
}
string
This item is quite special personally and changes the value to string type. The following built-in types are supported.
Also, since the string type is also converted to the string type, "
is escaped and output.
func main() {
type Sample struct {
ID string `json:",string"`
}
s := Sample{ID: "xxffid"}
out, _ := json.Marshal(s)
fmt.Println(string(out)) // []Since it is a byte type, it is converted to a string
// Output:
// {"ID":"\"xxffid\""}
}
The output order is similar to the order of the fields in the structure. However, things like map that are not in a fixed order are sorted alphabetically by key name. I wondered why this was the order, but considering the ease of testing, I feel like that.
func main() {
s := map[string]string{
"cup": "one",
"apple": "two",
"banana": "three",
}
out, _ := json.Marshal(s)
fmt.Println(string(out)) // []Since it is a byte type, it is converted to a string
// Output:
// {"apple":"two","banana":"three","cup":"one"}
}
Embedded types are possible in go language structures. Since this type does not specify a field name, there is no key name. Therefore, basically, the fields of the embedded structure are expanded and output.
func main() {
type Emb struct {
Content string
}
type Sample struct {
Emb
}
s := Sample{Emb: Emb{Content: "string"}}
out, _ := json.Marshal(s)
fmt.Println(string(out)) // []Since it is a byte type, it is converted to a string
// Output: {"Content":"string"}
}
Of course there are exceptions, as I said basic. In the go language, it is possible to declare a type for an array. In this case, the expansion will result in the array being expanded, so you don't know the name of the key. Therefore, the type name is the key name, except for the embedded type of the array.
func main() {
type Emb []string
type Sample struct {
Emb
}
s := Sample{Emb: Emb{"content1", "content2"}}
out, _ := json.Marshal(s)
fmt.Println(string(out)) // []Since it is a byte type, it is converted to a string
// Output:
// {"Emb":["content1","content2"]}
}
From the explanation so far, you can see that the key name is determined by various factors. However, that would result in a key collision. Therefore, go's json conversion has a priority. The priorities are shown below.
If there are multiple items with the same priority, no key value will be output and no error will be output. It is a behavior that seems to fit if you are not careful when deploying the embedded type.
There are various behaviors, but I think that many people find it bothersome to remember all of them and think about them one by one. So I created a tool to find out what json the struct outputs. https://github.com/komem3/stout
To use it, just specify the file path and structure name as shown below.
stout -path ./define.go SimpleStruct
I wrote it for this promotion.
Recommended Posts