Json序列化

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

序列化

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

/_src/practices/jsonify/quick-marshal.go

  1. package main
  2.  
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "log"
  7. )
  8.  
  9. type Pair struct {
  10. Name string
  11. Value int
  12. }
  13.  
  14. func main() {
  15. pair := Pair{
  16. Name: "bar",
  17. Value: 1,
  18. }
  19.  
  20. content, err := json.Marshal(pair)
  21. if err == nil {
  22. fmt.Printf("%s\n", content)
  23. } else {
  24. log.Fatal(pair)
  25. }
  26. }

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

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

静态序列化

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

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

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

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

/_src/practices/jsonify/static-marshal.go

  1. type Pair struct {
  2. Name string
  3. Value int
  4. }
  5.  
  6. type Map struct {
  7. Bar int
  8. Foo int
  9. }
  10.  
  11. type Message struct {
  12. Type string
  13. Data Object
  14. }

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

/_src/practices/jsonify/static-marshal.go

  1. content, err := json.Marshal(Message{
  2. Type: "map",
  3. Data: Map{
  4. Bar: 1,
  5. Foo: 2,
  6. },
  7. })

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

自定义字段名

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

/_src/practices/jsonify/static-marshal-with-tags.go

  1. type Pair struct {
  2. Name string `json:"name"`
  3. Value int `json:"value"`
  4. }
  5.  
  6. type Map struct {
  7. Bar int `json:"bar"`
  8. Foo int `json:"value"`
  9. }
  10.  
  11. type Message struct {
  12. Type string `json:"type"`
  13. Data Object `json:"data"`
  14. }

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

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

动态序列化

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

  1. json.dumps({
  2. "type": "map",
  3. "data": {
  4. "bar": 1,
  5. "foo": 2,
  6. },
  7. })

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

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

/_src/practices/jsonify/free-marshal.go

  1. type Object interface {}
  2. type Array []Object
  3.  
  4. type JsonObject map[string]Object
  5. type JsonArray Array

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

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

/_src/practices/jsonify/free-marshal.go

  1. content, err := json.Marshal(JsonObject{
  2. "type": "map",
  3. "data": JsonObject{
  4. "bar": 1,
  5. "foo": 2,
  6. },
  7. })

组装另一种数据类型:

/_src/practices/jsonify/free-marshal.go

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

下一步

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

../_images/wechat-mp-qrcode.png小菜学编程

参考文献