JSON 序列化和反序列化

上一节我们介绍了 xml 的使用,其实对于数据的序列化和反序列化还有一种更为常见的方式,那就是 JSON,尤其是在 http, rpc 的微服务调用中。

基础语法

在 Go 中我们主要使用官方的 encoding/json 包对 JSON 数据进行序列化和反序列化,主要使用方法有:

  • 序列化:

    1. func Marshal(v interface{}) ([]byte, error)
  • 反序列化:

    1. func Unmarshal(data []byte, v interface{}) error

简单例子:

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. func main() {
  7. var (
  8. data = `1`
  9. value int
  10. )
  11. err1 := json.Unmarshal([]byte(data), &value)
  12. fmt.Println("Unmarshal error is:", err1)
  13. fmt.Printf("Unmarshal value is: %T, %d \n", value, value)
  14. value2, err2 := json.Marshal(value)
  15. fmt.Println("Marshal error is:", err2)
  16. fmt.Printf("Marshal value is: %s \n", string(value2))
  17. }

当我们运行代码的时候可以得到如下输出结果:

  1. Unmarshal error is: <nil>
  2. Unmarshal value is: int, 1
  3. Marshal error is: <nil>
  4. Marshal value is: 1

在这个例子中,我们使用 UnmarshalMarshal 将一个整数的 JSON 二进制转化为 go int 数据。

注意:在实际应用中,我们在序列化和反序列化的时候,需要检查函数返回的 err, 如果 err 不为空,表示数据转化失败。

例如:我们把上面例子中 value 类型由 int 修改为 string 后再次运行代码,你将得到 Unmarshal error is: json: cannot unmarshal number into Go value of type string 的错误提醒。

数据对应关系

JSON 和 Go 数据类型对照表:

类型 JSON Go
bool true, false true, false
string “a” string(“a”)
整数 1 int(1), int32(1), int64(1) …
浮点数 3.14 float32(3.14), float64(3.14) …
数组 [1,2] [2]int{1,2}, []int{1, 2}
对象 Object {“a”: “b”} map[string]string, struct
未知类型 interface{}

例如:

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. func main() {
  7. var (
  8. d1 = `false`
  9. v1 bool
  10. )
  11. json.Unmarshal([]byte(d1), &v1)
  12. printHelper("d1", v1)
  13. var (
  14. d2 = `2`
  15. v2 int
  16. )
  17. json.Unmarshal([]byte(d2), &v2)
  18. printHelper("d2", v2)
  19. var (
  20. d3 = `3.14`
  21. v3 float32
  22. )
  23. json.Unmarshal([]byte(d3), &v3)
  24. printHelper("d3", v3)
  25. var (
  26. d4 = `[1,2]`
  27. v4 []int
  28. )
  29. json.Unmarshal([]byte(d4), &v4)
  30. printHelper("d4", v4)
  31. var (
  32. d5 = `{"a": "b"}`
  33. v5 map[string]string
  34. v6 interface{}
  35. )
  36. json.Unmarshal([]byte(d5), &v5)
  37. printHelper("d5", v5)
  38. json.Unmarshal([]byte(d5), &v6)
  39. printHelper("d5(interface{})", v6)
  40. }
  41. func printHelper(name string, value interface{}) {
  42. fmt.Printf("%s Unmarshal value is: %T, %v \n", name, value, value)
  43. }

运行代码我们可以得到如下输出结果:

  1. d1 Unmarshal value is: bool, false
  2. d2 Unmarshal value is: int, 2
  3. d3 Unmarshal value is: float32, 3.14
  4. d4 Unmarshal value is: []int, [1 2]
  5. d5 Unmarshal value is: map[string]string, map[a:b]
  6. d5(interface{}) Unmarshal value is: map[string]interface {}, map[a:b]

自定义数据类型

除了使用上面基础数据外,对于那些比较复杂的数据集合(Object),我们还可以使用自定义数据类型 struct 来转化。

  • Go 中关于 JSON 转化字段名的对应语法为:
  1. Field int `json:"myName"`
  • 如果我们想忽略那些空值的字段,我们可以使用 omitempty 选项:
  1. Field int `json:"myName,omitempty"`
  • 如果我们想忽略特定字段:
  1. Field int `json:"-"`

组合示例:

  1. type A struct {
  2. A int `json:"k"`
  3. B string `json:"b,omitempty"`
  4. C float64 `json:"-"`
  5. }

实际例子练习

假如我们有这样一段 JSON 数据,它表示一个学生的考试成绩,下面我们就来看看在 Go 中如何序列化和反序列化。

  • 数据准备:
  1. # data.json
  2. {
  3. "id": 1,
  4. "name": "小红",
  5. "results": [
  6. {
  7. "name": "语文",
  8. "score": 90
  9. },
  10. {
  11. "name": "数学",
  12. "score": 100
  13. }
  14. ]
  15. }
  • 反序列化:
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. )
  7. type Result struct {
  8. Name string `json:"name"`
  9. Score float64 `json:"score"`
  10. }
  11. type Student struct {
  12. Id int `json:"id"`
  13. Name string `json:"name"`
  14. Results []Result `json:"results"`
  15. }
  16. func main() {
  17. dat, _ := ioutil.ReadFile("data.json")
  18. var s Student
  19. json.Unmarshal(dat, &s)
  20. fmt.Printf("Student's result is: %v\n", s)
  21. }

运行代码输出结果为:

  1. Student's result is: {1 小红 [{语文 90} {数学 100}]}
  • 序列化:
  1. package main
  2. import (
  3. "encoding/json"
  4. "io/ioutil"
  5. )
  6. type Result struct {
  7. Name string `json:"name"`
  8. Score float64 `json:"score"`
  9. }
  10. type Student struct {
  11. Id int `json:"id"`
  12. Name string `json:"name"`
  13. Results []Result `json:"results"`
  14. }
  15. func main() {
  16. s := Student{
  17. Id: 1,
  18. Name: "小红",
  19. Results: []Result{
  20. Result{
  21. Name: "语文",
  22. Score: 90,
  23. },
  24. Result{
  25. Name: "数学",
  26. Score: 100,
  27. },
  28. },
  29. }
  30. dat, _ := json.Marshal(s)
  31. ioutil.WriteFile("data2.json", dat, 0755)
  32. }

当我们运行代码后,打开 data2.json 文件,将看到如下内容:

  1. {
  2. "id": 1,
  3. "name": "小红",
  4. "results": [
  5. {
  6. "name": "语文",
  7. "score": 90
  8. },
  9. {
  10. "name": "数学",
  11. "score": 100
  12. }
  13. ]
  14. }