golang 结构体 struct 转 json 字符串

https://www.sohamkamani.com/golang/omitempty/

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
type Dog struct {
Breed string
WeightKg int
}

func main() {
d := Dog{
Breed: "dalmation",
WeightKg: 45,
}
b, _ := json.Marshal(d)
fmt.Println(string(b))
}

输出:

1
{"Breed":"dalmation","WeightKg":45}

如果 去掉 结构体 中的 WeightKg 属性 又会如何呢?

1
2
3
4
5
6
7
8
func main() {
d := Dog{
Breed: "pug",
}
b, _ := json.Marshal(d)
fmt.Println(string(b))
}

输出如下:

1
2
{"Breed":"pug","WeightKg":0},

WeightKg 是 0 了, 我们可能更希望 是 “WeightKg”:null, 或者 不要带上 这个属性了。

因为我们没给结构体中这个属性赋值,希望的结构就不要带上这个。

omitempty 标签

这中情况 可以使用 omitempty 标签

1
2
3
4
5
6
7
8
9
10
11
12
type Dog struct {
Breed string
WeightKg int `json:",omitempty"`
}

func main() {
d := Dog{
Breed: "dalmation",
}
b, _ := json.Marshal(d)
fmt.Println(string(b))
}

这个时候 就会 输出 如下:

1
{"Breed":"dalmation"}

Values that Cannot Be Omitted

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type dimension struct {
Height int
Width int
}

type Dog struct {
Breed string
WeightKg int
Size dimension `json:",omitempty"`
}

func main() {
d := Dog{
Breed: "pug",
}
b, _ := json.Marshal(d)
fmt.Println(string(b))
}

如果 嵌套 一个 结构体,这时候 又出问题了,这样输出如下:

1
2
{"Breed":"pug","WeightKg":0,"Size":{"Height":0,"Width":0}}

这个情况 我们没有给 Size 这个属性 赋值,但是 json 打印处理的 还是带上这个属性了,

解决方法是 使用 指针

1
2
3
4
5
6
type Dog struct {
Breed string
WeightKg int
// Now `Size` is a pointer to a `dimension` instance
Size *dimension `json:",omitempty"`
}

使用指针之后 输出如下:

1
{"Breed":"pug","WeightKg":0}

The Difference Between 0, “” and Nil

What would be the output of this code?

1
2
3
4
5
6
7
8
9
10
11
12
13
type Dog struct {
Age *int `json:",omitempty"`
}

func main() {
age := 0
d := Dog{
Age: &age,
}

b, _ := json.Marshal(d)
fmt.Println(string(b))
}

输出是:

1
2
3

{"Age":0}

1
2
3
4
5
6
7
8
9
10
11
type Restaurant struct {
NumberOfCustomers int `json:",omitempty"`
}

func main() {
d := Restaurant{
NumberOfCustomers: 0,
}
b, _ := json.Marshal(d)
fmt.Println(string(b))
}

输出:

1
{}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type Restaurant struct {
NumberOfCustomers *int `json:",omitempty"`
}
func main() {
d1 := Restaurant{}
b, _ := json.Marshal(d1)
fmt.Println(string(b))
//Prints: {}

n := 0
d2 := Restaurant{
NumberOfCustomers: &n,
}
b, _ = json.Marshal(d2)
fmt.Println(string(b))
//Prints: {"NumberOfCustomers":0}
}

输出:

1
2
{"NumberOfCustomers":0}

When to use “omitempty”

Although we’ve gone through the usage of omitempty, the most important thing to remember is that it should be used sparingly. If the application consuming the JSON objects generated by the Go application doesn’t differentiate between undefined keys and zero value keys, then there’s really no reason to use the omitempty tag in the first place.

If you do decide to use it, then make sure that Go’s definition of “empty” matches your application’s.

To learn how to work with JSON in Go in greater detail, you can read my other post on parsing JSON in Go.

https://www.sohamkamani.com/golang/json/

其他

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package main

import (
"bytes"
"encoding/json"
"fmt"
"io"
)

func NewRequest(body interface{}) {
var buf io.ReadWriter
if body != nil {
buf = &bytes.Buffer{}
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(false)
err := enc.Encode(body)
if err != nil {
fmt.Println(err)
}
}
}

type EditFortestRequest struct {
Name string `json:"name,omitempty"`
Path string `json:"path,omitempty"`
Description string `json:"description,omitempty"`
Enable bool `json:"enable,omitempty"`
Age int `json:"age,omitempty"`
}
type NewFortestRequest struct {
Name *string `json:"name,omitempty"`
Path *string `json:"path,omitempty"`
Description *string `json:"description,omitempty"`
Enable *bool `json:"enable,omitempty"`
}

func test1() {
body := &EditFortestRequest{
Name: "name ",
Path: "path ",
Age: 0,
}
NewRequest(body)
}
func test2() {
name := "name pointer"
path := "path pointer"
body := &NewFortestRequest{
Name: &name,
Path: &path,
}
NewRequest(body)
}
func main() {
test1()
}

body = {interface {} | *main.EditRequest}
Name = {string} "name "
Path = {string} "path "
Description = {string} ""
Enable = {bool} false
Age = {int} 0 // 不用指针这里 是 默认的 0值,没有传入呢 还是 使用者本身传的就是个0值呢,这样 转成json的时候是 没这个 age 属性的。

{"name":"name","path":"path"}


1
2
3
4
5
6
7
8

body = {interface {} | *main.NewFortestRequest}
Name = {*string | 0xc000116250} "name pointer"
Path = {*string | 0xc000116260} "path pointer"
Description = {*string} nil
Enable = {*bool} nil

{"name":"name","path":"path"}
1
2
3
4
5
6
7
8
9
body = {interface {} | *main.NewFortestRequest}
Name = {*string | 0xc000010270} "name pointer"
Path = {*string | 0xc000010280} "path pointer"
Description = {*string} nil
Enable = {*bool} nil
Age = {*int | 0xc00001e160} 0 # 这个不是nil 表明使用者正式传入了这个 整数0值了。这样转换出来的 json 里面就有这个 属性

{"name":"name pointer","path":"path pointer","age":0}