042-遍地开花的 json

json 是一种结构化的字符串,因为它的编码和解码都有非常成熟的 library 支持,有些语言甚至已经原生支持编码和解码,比如 Go 就是。另一方面,json 数据有着易读易编写的特性,因此被广泛应用于网络数据的传输。

如果你还不知道 json 为何物,那就先阅读一下相关知识:http://www.w3school.com.cn/json/

1. 将结构体序列化成 json

type Movie struct {
    Title    string
    Year     int
    Color    bool
    Actors   []string
    duration int
}

m := Movie {
    Title: "Casablanca",
    Year: 1942,
    Color: false,
    Actors: []string{
        "Humphrey Bogart",
        "Ingrid Bergman",
    },
    duration: 1000,
}

看上面的代码,如果要将对象 m 序列化成 json,最后结果应该像这样(这是一段字段串):

{
    "Title":"Casablanca",
    "Year":1942,
    "Color":false,
    "Actors":[
        "Humphrey Bogart",
        "Ingrid Bergman"
    ],
    "duration": 1000
}

Go 提供了 encoding/json 包,这个包里有很多函数都可以将 go 的结构体对象和 json 字符串之间进行互转。

1.1 encoding/json 包

先来看这个函数:

// 将结构体序列化成 json 字符串
func Marshal(v interface{}) ([]byte, error)

注意这里有一个新的类型 interface{},这在很久前你就已经见过了,它有点类似 C++ 的抽象类,主要用来定义接口。在这里你暂且理解成如果参数类型是 interface{},表示可以接受任何类型的数据,这就也有点像 C/C++ 里的 void*

b, _ := json.Marshal(m)
fmt.Printf("%s\n", b)

运行后输出:

{"Title":"Casablanca","Year":1942,"Color":false,"Actors":["Humphrey Bogart","Ingrid Bergman"]}

不过,似乎上面的输出少了点东西?对,duration 字段好像不见了。这里需要解释一下:go 对未导出的字段,在序列化成 json 的时候会忽略

在我们的结构体定义中,duration 是小写字母开头的,因此是一个未导出字段,最后序列化的时候就看不到了。

1.2 struct tag

go 允许通过一些用户自定义的 tag 标签,来控制序列化的行为以达到特殊效果。举例说明:

type Movie struct {
    Title    string   `json:"title"`
    Year     int      `json:"release"`
    Color    bool     `json:"color"`
    Actors   []string `json:"actors"`
    duration int
}

重新定义 Movie 结构体后,再次使用 marshal 序列化,看看结果如何。

// 注意这里,使用了另一个新的序列化函数 MarshalIndent,它能使输出的结果更加 Pretty.
b, _ := json.MarshalIndent(m, "", "    ")
fmt.Printf("%s\n", b)

结果输出:

{
    "title": "Casablanca",
    "release": 1942,
    "color": false,
    "actors": [
        "Humphrey Bogart",
        "Ingrid Bergman"
    ]
}

不知道你有没有什么发现?是的,所有字段的名称都变了。tag 的语法非常简单,在字段后后面使用反引号将 key:value 括起来就行了。tag 允许有多个 key:value,以空格进行分隔。另外,一个 key 也可以有多个 value,以逗号分隔,例如:

Year int `json:year,omitempty xml:release`

如果 key 是 json,第一个 value 表示序列成 json 后字段的新名称,第二个 value 是一个控制选项 omitempty,表示如果当前字段是零值,则序列化成 json 后忽略该字段。

另外当 key 是 xml 时,和 json 类似。比如上面的序列化成 xml 后,字段名称就是 release.

有关 tag 的一些知识我们后面还会接触到,以后遇到其它的再继续说明。这里有一篇官方文档比较全面,可以参考一下:https://github.com/golang/go/wiki/Well-known-struct-tags

2. 将 json 反序列化成结构体对象

// 将 json 字符串反序列化成结构体
func Unmarshal(data []byte, v interface{}) error

这个函数也很简单,来个例子就明白了:

var m Movie
// 注意这里,字符串也可以使用反引号。不使用双引号是因为 json 串里已经包含了双引号
b := `{"title":"Casablanca","release":1942,"color":false,"actors":["Humphrey Bogart","Ingrid Bergman"]}`
json.Unmarshal([]byte(b), &m)
fmt.Printf("%#v\n", m)


这里写图片描述
图1 反序列化

3. 总结

  • 掌握结构体和 json 字符串间的序列化和反序列化
  • 掌握 struct tag

练习:查阅一下 encoding/json 包里还有其它哪些函数。

猜你喜欢

转载自blog.csdn.net/q1007729991/article/details/80370957