json数据格式是目前世界上使用很广的一种数据格式之一,目前很多应用之间的交互都是使用json格式,最常见的如开发APP的时候,接口返回的数据一般都是json格式。
golang官方也提供了标准库对json格式的数据进行解码和编码,依据json数据标准规范4627版(RFC 4627),说起规范这种东西,真的要感觉这些大佬们,因为规范制定后,全球都按照这种规范来做,省去了不少的交流沟通成本。
golang中对json数据的处理主要使用encoding/json包,其中最常用的函数一个是Marshal——用来编码,一个是Unmarshal——用来解码,先看看json字符串的解码。
Unmarshal解码
先看下Unmarshal函数的原型:
func Unmarshal(data []byte, v interface{}) error
package main import ( "encoding/json" "fmt" ) func main() { // json格式字符串 var jsonUsers = []byte(`[ {"id": "1", "name": "Anny"}, {"id": "2", "name": "Tom"} ]`) // 用结构体User进行接收 // Id属性后的``内的内容表示转化json数据时的一个设定 // 例如:`json:"id,string"`,表示对应的json格式字符串键值为id,类型为字符串 // `json:"name"`,表示对应的json格式字符串键值为name type User struct { Id int `json:"id,string"` Name string `json:"name"` } // 因为json格式字符串是个数组格式,这里也要定义数组 var users []User err := json.Unmarshal(jsonUsers, &users) if err != nil { panic(err) } fmt.Printf("%+v\n", users) // output: [{Id:1 Name:Anny} {Id:2 Name:Tom}] }
代码注释比较详细,不再多说明了,值得一提的是结构体的标签(Tag)内容,设计非常巧妙,可以查看以前写的这篇文章:golang中struct成员变量的标签(Tag)说明和获取方式。
另外查看Unmarshal这个函数,可以看到存储解析内容的变量类型是interface,也就说除了结构体外也可以使用其它类型进行接收,这里用字典(map)写了一个示例。
package main import ( "encoding/json" "fmt" ) func main() { // json格式字符串 var jsonUsers = []byte(`[ {"id": "1", "name": "Anny"}, {"id": "2", "name": "Tom"} ]`) // 尝试用字典进行接收 // 因为json格式的键通常为字符串类型 // 值有可能为各种类型,如果整形、浮点、数组、对象等 // 所以map存储的值定义为interface{}类型 var users []map[string]interface{} err := json.Unmarshal(jsonUsers, &users) if err != nil { panic(err) } fmt.Printf("%+v\n", users) // output: [map[id:1 name:Anny] map[id:2 name:Tom]] }
其实自己觉得用字典(map)来接收后续的流程不太好处理,如果要使用字典值(interface{})则需要对类型进行逐一判断,形如:
switch t := v.(type) { case bool: case int: default: }
接下来看下编码吧。
Marshal编码
func Marshal(v interface{}) ([]byte, error)
先看下从struct类型编码成json格式字符串的示例
package main import ( "encoding/json" "fmt" ) func main() { // 声明一个结构体 type ColorGroup struct { ID int `json:"id,string"` Name string `json:"name,omitempty"` Colors []string `json:"colors"` } // 对ColorGroup类型的变量进行编码 group := ColorGroup{ ID: 1, Name: "Reds", Colors: []string{"Crimson", "Red", "Ruby", "Maroon"}, } b, err := json.Marshal(group) if err != nil { panic(err) } fmt.Println(string(b)) // output: {"id":"1","name":"Reds","colors":["Crimson","Red","Ruby","Maroon"]} // 如果没有设置Name属性值,因为标记为了omitempty属性,则在编码成json的时候会忽略Name属性 group = ColorGroup{ ID: 1, Colors: []string{"Crimson", "Red", "Ruby", "Maroon"}, } b, err = json.Marshal(group) if err != nil { panic(err) } fmt.Println(string(b)) // output: {"id":"1","colors":["Crimson","Red","Ruby","Maroon"]} // 如果没有设置Colors值,因为没有omitempty属性,会输出nil group = ColorGroup{ ID: 1, Name: "Reds", } b, err = json.Marshal(group) if err != nil { panic(err) } fmt.Println(string(b)) // output: {"id":"1","name":"Reds","colors":null} }
同解码一样,也可以将map类型进行编码。
package main import ( "encoding/json" "fmt" ) func main() { m := map[string]interface{}{ "id": 1, "name": "Socrates", "friends": []string{"Plato", "Aristotle"}, } b, err := json.Marshal(m) if err != nil { panic(err) } fmt.Println(string(b)) }
在实际开的时候,对map类型进行编码自己比较常用,通常用来api接口的数据输出。因为外围不需要再处理什么东西了,获取数据的函数会直接返回map[string]interface{}类型的数据,只需要json编码一下输出就可以了,处理起来就简单很多。
转载请注明:快乐编程 » golang中json编码和解码