This paper sorted out some of the problems and solutions we often encounter in the go language JSON data and structure conversion.

Basic serialization

First, let’s look at the basic usage of Json. Marshal and json.Unmarshal in Go.

Type Person struct {Name string Age int64 Weight float64} func main() {p1 := Person{Name: "small ", Age: 18, Weight: Struct -> json string b, err := json.Marshal(p1) if err! = nil { fmt.Printf("json.Marshal failed, err:%v\n", err) return } fmt.Printf("str:%s\n", b) // json string -> struct var p2 Person err = json.Unmarshal(b, &p2) if err ! = nil { fmt.Printf("json.Unmarshal failed, err:%v\n", err) return } fmt.Printf("p2:%#v\n", p2) }Copy the code

Output:

STR: {" Name ":" xiao Ming ", "Age" : 18, "Weight" : 71.5} p2: main. Person {Name: "Ming", the Age: 18, Weight: 71.5}Copy the code

Structure tag introduction

The Tag is the meta information of the structure that can be read at runtime via reflection. The Tag is defined after the structure field and is enclosed by a pair of backquotes in the following format:

`key1:"value1" key2:"value2"`
Copy the code
  1. A tag structure consists of one or more key-value pairs. Keys and values are separated by colons, and values are enclosed in double quotes.
  2. Multiple key-value pairs can be set for the same structure field, with Spaces separating the different key-value pairs.

Use the JSON tag to specify the field name

Serialization and deserialization by default, we use the structure’s field names. We can specify the field names generated by JSON serialization by adding tags to the structure fields.

Type Person struct {Name string 'json:" Name "' // Specify lowercase Name Age int64 Weight when serializing/deserializing json float64 }Copy the code

Ignore a field

If you want to ignore a field in the structure during json serialization/deserialization, you can add – to the tag as follows.

Type Person struct {Name string 'json:" Name "' // Specify lowercase Name Age int64 for json serialization/deserialization Weight float64 'json:"-"' // Specifies json serialization/deserialization to ignore this field}Copy the code

Ignore null-valued fields

When fields in a struct have no value, json.marshal () does not ignore these fields when serialized, but defaults to output fields with type zero values (for example, zero values for int and float, “” for string, nil for object type). If you want to ignore these fields when serializing the sequence, you can add an omitEmpty tag to the corresponding field.

Here’s an example:

type User struct { Name string `json:"name"` Email string `json:"email"` Hobby []string `json:"hobby"` } func OmitemptyDemo () {u1 := User{Name: "",} // struct -> json string b, err := json.Marshal(u1) if err! = nil { fmt.Printf("json.Marshal failed, err:%v\n", err) return } fmt.Printf("str:%s\n", b) }Copy the code

Output result:

STR: {" name ":" xiao Ming ", "email" : ""," hobby ": null}Copy the code

If you want to remove null-valued fields from the final serialization, you can define the structure as follows:

// Add omitEmpty to the tag and ignore the empty value. // Note that omitEmpty adds up to json tag values. Type User struct {Name String 'json:" Name "' Email String 'JSON :" Email, omitEmpty "' Hobby [] String `json:"hobby,omitempty"` }Copy the code

At this point, execute the above omitemptyDemo, and the output is as follows:

STR :{"name":" xiaoming "} // There are no email and Hobby fields in the serialization resultCopy the code

As an aside, when working with a database using GORM, we often encounter problems where we want to ignore the modification of specified fields, such as the associated entities in a structure, which only want to be displayed in JSON, and which are ignored when submitting a form, which I will sort out in a separate article.

The null value field of the nested structure is ignored

Let’s start with several examples of nested structures:

type User struct { Name string `json:"name"` Email string `json:"email,omitempty"` Hobby []string `json:"hobby,omitempty"` Profile } type Profile struct { Website string `json:"site"` Slogan string `json:"slogan"` } Func nestedStructDemo() {u1 := User{Name: "小 小 ", Hobby: [] String {" soccer ", "basketball "},} b, err := json.Marshal(u1) if err! = nil { fmt.Printf("json.Marshal failed, err:%v\n", err) return } fmt.Printf("str:%s\n", b) }Copy the code

The serialized JSON string is single-layer when profiles are anonymously nested:

STR: {" name ":" xiao Ming ", "hobby" : / "football", "basketball", "site" : ""," slogan ":" "}Copy the code

To change to a nested JSON string, change to a named nested or defined field tag:

type User struct { Name string `json:"name"` Email string `json:"email,omitempty"` Hobby []string `json:"hobby,omitempty"` Profile `json:"profile"` } // STR: {" name ":" xiao Ming ", "hobby" : [" football ", "basketball"], "profile" : {" site ":" ", "slogan" : ""}} want to nested structure of null values, ignore the field, only add omitempty is not enough:  type User struct { Name string `json:"name"` Email string `json:"email,omitempty"` Hobby []string `json:"hobby,omitempty"` Profile `json:"profile,omitempty"` } // STR: {" name ":" xiao Ming ", "hobby" : [" football ", "basketball"], "profile" : {" site ":" ", "slogan" : ""}}Copy the code

We also need to use nested structure Pointers:

type User struct { Name string `json:"name"` Email string `json:"email,omitempty"` Hobby []string ` json: "hobby, omitempty ` * Profile ` json:" Profile, omitempty ` / / "is the key here} / / STR: {" name" : "xiao Ming", "hobby" : [" football ", "basketball"]}Copy the code

Null value fields are ignored without modifying the original structure

We need json to serialize the User, but we don’t want to serialize the Password as well, and we don’t want to modify the User structure, so we can create another structure PublicUser anonymously nested User, and specify the Password field as the pointer type of the anonymous structure. Add omitemptyTag as follows:

Type User struct {Name string 'json:" Name "' Password string 'json:" Password "'} type PublicUser struct {*User // anonymous nesting Password *struct{} 'json:" Password,omitempty"'} func omitPasswordDemo() {u1 := User{Name: "小 小 ", Password: "123456", } b, err := json.Marshal(PublicUser{User: &u1}) if err ! Printf("json.Marshal u1 failed, err:%v\n", err) return} FMT.Printf(" STR :%s\n", b) // STR :{"name":" small "}}Copy the code

Gracefully handles numbers in string format

In some cases, the front-end may use string numbers in the json data. In this case, we can add a string to the structure tag to tell the json package to parse the corresponding field data from the string:

Type Card struct {ID int64 'json:" ID,string"' // Add String tag Score float64 'json:" Score,string"' // Add String tag} func intAndStringDemo() { jsonStr1 := `{"id": "1234567","score": "88.50"} 'var c1 Card if err := json.Unmarshal([]byte(jsonStr1) &c1); err ! = nil { fmt.Printf("json.Unmarsha jsonStr1 failed, err:%v\n", err) return } fmt.Printf("c1:%#v\n", C1) // c1:main.Card{ID:1234567, Score:88.5}}Copy the code

conclusion

Today, I just sorted out some of the skills of using JSON. Json is an indispensable part of the actual project. Today, I set a flag and the next article will sort out the skills of using GORM.

About me

I am committed to becoming the king of pirates, welcome to join my voyage. I have prepared a gift for you by searching “Wang Zhongyang” on wechat public account.