Json序列化

JSON 是目前最为流行的序列化手段, Go 语言内置 encoding/json 包用于 JSON 序列化 / 反序列化 操作。 本文以详细代码示例,演示 encoding/json 包的使用方式。

序列化

对于已有类型,序列化只需一行代码:

/_src/practices/jsonify/quick-marshal.go
 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
package main

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

type Pair struct {
    Name string
    Value int
}

func main() {
    pair := Pair{
        Name: "bar",
        Value: 1,
    }

    content, err := json.Marshal(pair)
    if err == nil {
        fmt.Printf("%s\n", content)
    } else {
        log.Fatal(pair)
    }
}

例子第 9-12 行,定义了一个 Pair 类型,包含两个字段; 第 15-18 行,定义了一个 Pair 变量并初始化; 第 20 行对该变量进行 JSON 序列化操作,结果如下:

{"Name":"bar","Value":1}

静态序列化

为了生成 JSON 数据,如果类型未定义,则需要先定义新的数据类型。

例如,为了临时生成以下两种不同格式的 JSON 数据:

{"Type":"map","Data":{"Bar":1,"Foo":2}}
{"Type":"list","Data":[{"Name":"Bar","Value":1},{"Name":"Foo","Value":2}]}

可以先定义以下数据类型:

/_src/practices/jsonify/static-marshal.go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
type Pair struct {
    Name string
    Value int
}

type Map struct {
    Bar int
    Foo int
}

type Message struct {
    Type string
    Data Object
}

然后,初始化数据并序列化:

/_src/practices/jsonify/static-marshal.go
1
2
3
4
5
6
7
    content, err := json.Marshal(Message{
        Type: "map",
        Data: Map{
            Bar: 1,
            Foo: 2,
        },
    })

这便是 静态序列化 方式,为了生成 JSON 数据而定义新的数据类型,好比用牛刀杀鸡。 接着,在 动态序列化 一节,介绍一种灵活构建 JSON 数据的方法,更加简便。

自定义字段名

序列化结构体,字段名默认与结构体一致。 结构体字段名通过首字母大小写控制访问,因此有时并不满足需要。 例如,结构体中的字段名是驼峰风格,而 JSON 字段名却要求用小写字母以及下划线…… 这时,只能为结构体字段打上辅助标签:

/_src/practices/jsonify/static-marshal-with-tags.go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
type Pair struct {
    Name string `json:"name"`
    Value int `json:"value"`
}

type Map struct {
    Bar int `json:"bar"`
    Foo int `json:"value"`
}

type Message struct {
    Type string `json:"type"`
    Data Object `json:"data"`
}

这样一来,序列化结果便满足要求了:

{"type":"map","data":{"bar":1,"value":2}}
{"type":"list","data":[{"name":"Bar","value":1},{"name":"Foo","value":2}]}

动态序列化

Python 之类的动态类型语言,我们可以非常自由地组织数据,随时随地:

json.dumps({
    "type": "map",
    "data": {
        "bar": 1,
        "foo": 2,
    },
})

然而, Go 不是动态类型语言,是不是就没有办法实现动态序列化了呢?

当然不是了,我们可以通过空接口实现。 首先定义几种基本类型:

/_src/practices/jsonify/free-marshal.go
1
2
3
4
5
type Object interface {}
type Array []Object

type JsonObject map[string]Object
type JsonArray Array

其中, Object 可以是任意类型; Array 可以是任意类型组成的 数组JsonOject 是一个 映射表 ,键为字符类型,值可以是任意类型; JsonArrayArray 相同。

有了这些基本类型,我们也可以非常灵活的组装数据,同样随时随地:

/_src/practices/jsonify/free-marshal.go
1
2
3
4
5
6
7
    content, err := json.Marshal(JsonObject{
        "type": "map",
        "data": JsonObject{
            "bar": 1,
            "foo": 2,
        },
    })

组装另一种数据类型:

/_src/practices/jsonify/free-marshal.go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    content, err = json.Marshal(JsonObject{
        "type": "list",
        "data": Array{
            JsonObject{
                "name": "bar",
                "value": 1,
            },
            JsonObject{
                "name": "foo",
                "value": 2,
            },
        },
    })

下一步

订阅更新,获取更多学习资料,请关注我们的 微信公众号

../_images/wechat-mp-qrcode.png

小菜学编程