Skip to content

json

https://golang.org/pkg/encoding/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
package main

import (
    "encoding/json"
    "fmt"
)

type Host struct {
    IP   string
    Name string
}

func main() {

    b := []byte(`{"IP": "192.168.11.22", "name": "SKY"}`)

    m := Host{}

    err := json.Unmarshal(b, &m)
    if err != nil {

        fmt.Println("Umarshal failed:", err)
        return
    }

    fmt.Println("m: ", m)
    fmt.Println("m.IP: ", m.IP)
    fmt.Println("m.Name: ", m.Name)
}

输出:

1
2
3
m:  {192.168.11.22 SKY}
m.IP:  192.168.11.22
m.Name:  SKY
 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
68
69
70
71
72
73
74
75
76
77
package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type response1 struct {
    Page   int
    Fruits []string
}

type response2 struct {
    Page   int      `json:"page"`
    Fruits []string `json:"fruits"`
}

func main() {
    bolB, _ := json.Marshal(true)
    fmt.Println(string(bolB))

    intB, _ := json.Marshal(1)
    fmt.Println(string(intB))

    fltB, _ := json.Marshal(2.34)
    fmt.Println(string(fltB))

    strB, _ := json.Marshal("gopher")
    fmt.Println(string(strB))

    slcD := []string{"apple", "peach", "pear"}
    slcB, _ := json.Marshal(slcD)
    fmt.Println(string(slcB))

    mapD := map[string]int{"apple": 5, "lettuce": 7}
    mapB, _ := json.Marshal(mapD)
    fmt.Println(string(mapB))

    res1D := &response1{
        Page:   1,
        Fruits: []string{"apple", "peach", "pear"}}
    res1B, _ := json.Marshal(res1D)
    fmt.Println(string(res1B))

    res2D := &response2{
        Page:   1,
        Fruits: []string{"apple", "peach", "pear"}}
    res2B, _ := json.Marshal(res2D)
    fmt.Println(string(res2B))

    byt := []byte(`{"num":6.13,"strs":["a","b"]}`)

    var dat map[string]interface{}

    if err := json.Unmarshal(byt, &dat); err != nil {
        panic(err)
    }
    fmt.Println(dat)

    num := dat["num"].(float64)
    fmt.Println(num)

    strs := dat["strs"].([]interface{})
    str1 := strs[0].(string)
    fmt.Println(str1)

    str := `{"page": 1, "fruits": ["apple", "peach"]}`
    res := response2{}
    json.Unmarshal([]byte(str), &res)
    fmt.Println(res)
    fmt.Println(res.Fruits[0])

    enc := json.NewEncoder(os.Stdout)
    d := map[string]int{"apple": 5, "lettuce": 7}
    enc.Encode(d)
}

输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
true
1
2.34
"gopher"
["apple","peach","pear"]
{"apple":5,"lettuce":7}
{"Page":1,"Fruits":["apple","peach","pear"]}
{"page":1,"fruits":["apple","peach","pear"]}
map[num:6.13 strs:[a b]]
6.13
a
{1 [apple peach]}
apple
{"apple":5,"lettuce":7}

枚举类型

 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
package main

import (
    "encoding/json"
    "fmt"
    "log"
    "strings"
)

type Side int

const (
    BUY Side = iota
    SELL
)

func (side *Side) UnmarshalJSON(b []byte) error {
    var s string
    if err := json.Unmarshal(b, &s); err != nil {
        return err
    }
    switch strings.ToLower(s) {
    case "buy":
        *side = BUY
    case "sell":
        *side = SELL
    }

    return nil
}

func main() {

    blob := `["buy","Buy","BUY","sell","Sell","SELL","SElL"]`

    var sides []Side

    if err := json.Unmarshal([]byte(blob), &sides); err != nil {
        log.Fatal(err)
    }
    fmt.Println(sides)
}

输出:

1
[0 0 0 1 1 1 1]

map

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
    "encoding/json"
    "fmt"
    "log"
)

func main() {

    blob := `{"a": 1, "bbbb": 2}`

    var dic map[string]int

    if err := json.Unmarshal([]byte(blob), &dic); err != nil {
        log.Fatal(err)
    }

    for k, v := range dic {
        fmt.Println(k, v)
    }
}

输出:

1
2
bbbb 2
a 1

消息字段不匹配

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package main

import (
    "encoding/json"
    "fmt"
)

type Node struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    message := `{"name": "hhh", "age": 233, "sex": "man"}`
    node := Node{}
    json.Unmarshal([]byte(message), &node)
    fmt.Printf("%+v %s %d\n", node, node.Name, node.Age)
}
// {Name:hhh Age:233} hhh 233
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package main

import (
    "encoding/json"
    "fmt"
)

type Node struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    message := `{"name": "hhh"}`
    node := Node{}
    json.Unmarshal([]byte(message), &node)
    fmt.Printf("%+v %s %d\n", node, node.Name, node.Age)
}
// {Name:hhh Age:0} hhh 0

omitempty

我们可以在 Golang 的结构体定义中添加 omitempty 关键字,来表示这条信息如果没有提供,在序列化成 json 的时候就不要包含其默认值

带来方便的同时,使用 omitempty 也有些小陷阱,一个是该关键字无法忽略掉嵌套结构体

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
type address struct {
    Street     string     `json:"street"`
    Ste        string     `json:"suite,omitempty"`
    City       string     `json:"city"`
    State      string     `json:"state"`
    Zipcode    string     `json:"zipcode"`
    Coordinate coordinate `json:"coordinate,omitempty"`
}

type coordinate struct {
    Lat float64 `json:"latitude"`
    Lng float64 `json:"longitude"`
}

读入原来的地址数据,处理后序列化输出,我们就会发现即使加上了 omitempty 关键字,输出的 json 还是带上了一个空的坐标信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "street": "200 Larkin St",
    "city": "San Francisco",
    "state": "CA",
    "zipcode": "94102",
    "coordinate": {
        "latitude": 0,
        "longitude": 0
    }
}

为了达到我们想要的效果,可以把坐标定义为指针类型,这样 Golang 就能知道一个指针的“空值”是多少了,否则面对一个我们自定义的结构, Golang 是猜不出我们想要的空值的。于是有了如下的结构体定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
type address struct {
    Street     string      `json:"street"`
    Ste        string      `json:"suite,omitempty"`
    City       string      `json:"city"`
    State      string      `json:"state"`
    Zipcode    string      `json:"zipcode"`
    Coordinate *coordinate `json:"coordinate,omitempty"`
}

type coordinate struct {
    Lat float64 `json:"latitude"`
    Lng float64 `json:"longitude"`
}

另一个“陷阱”是,对于用 omitempty 定义的 field ,如果给它赋的值恰好等于默认空值的话,在转为 json 之后也不会输出这个 field 。
比如说上面定义的经纬度坐标结构体,如果我们将经纬度两个 field 都加上 omitempty

1
2
3
4
type coordinate struct {
    Lat float64 `json:"latitude,omitempty"`
    Lng float64 `json:"longitude,omitempty"`
}

然后我们对非洲几内亚湾的“原点坐标”非常感兴趣,于是编写了如下代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func main() {
    cData := `{
        "latitude": 0.0,
        "longitude": 0.0
    }`
    c := new(coordinate)
    json.Unmarshal([]byte(cData), &c)

        // 具体处理逻辑...

    coordinateBytes, _ := json.MarshalIndent(c, "", "    ")
    fmt.Printf("%s\n", string(coordinateBytes))
}

最终我们得到了一个

1
{}

https://old-panda.com/2019/12/11/golang-omitempty/