golang 标准库 encoding-json


这个包可以实现json的编码和解码,就是将json字符串转换为struct,或者将struct转换为json。

核心的两个函数

编码函数 Marshal

func Marshal(v interface{}) ([]byte, error)

将 struct 或 map 编码成json,可以接收任意类型

结构体转换为json

package main  
  
import (  
   "encoding/json"  
   "fmt")  
  
type Person struct {  
   Name  string  
   Age   int  
   Email string  
}  
  
func Marsha() {  
   p := Person{  
      Name:  "tom",  
      Age:   20,  
      Email: "[email protected]",  
   }  
   b, _ := json.Marshal(p)  
   fmt.Printf("b: %v\n", string(b))  
}  
func main() {  
   Marsha()  
}

map 转换为json

package main  
  
import (  
   "encoding/json"  
   "fmt")  
  
type Person struct {  
   Name  string  
   Age   int  
   Email string  
}  
  
func Marsha() {  
   p := make(map[string]interface{}, 20)  
   p["名称"] = "张三"  
   p["性别"] = "男"  
   p["年龄"] = "18"  
   b, _ := json.Marshal(p)  
   fmt.Printf("b: %v\n", string(b))  
}  
func main() {  
   Marsha()  
}

解码函数 Unmarshal

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

将json转码成struct结构体 或是 map

此函数的关键点在与 v 的数据类型,但是建议还是使用 结构体作为 v 的类型,毕竟可以使用 tag 标签来更加精准的解析数据
特别注意:第二次参数必须传入地址,否则修改不成功

json 转 map

package main  
  
import (  
   "encoding/json"  
   "fmt")  
  
type Person struct {  
   Name  string  
   Age   int  
   Email string  
}  
  
func Marsha() []byte {  
   p := make(map[string]interface{}, 20)  
   p["名称"] = "张三"  
   p["性别"] = "男"  
   p["年龄"] = "18"  
   b, _ := json.Marshal(p)  
   return b  
}  
func Unmarshal(b []byte) {  
   var m map[string]interface{}  
   json.Unmarshal(b, &m)  
   fmt.Printf("%v\n", m)  
}  
func main() {  
   Unmarshal(Marsha())  
}

json转换为结构体

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name   string
	Age    int
	Gender string
}

func Marsha() []byte {
	p := make(map[string]interface{}, 20)
	p["name"] = "张三"
	p["gender"] = "男"
	p["age"] = "18"
	b, _ := json.Marshal(p)
	return b
}
func Unmarshal(b []byte) {
	var m Person
	json.Unmarshal(b, &m)
	fmt.Printf("%v\n", m)
}
func main() {
	Unmarshal(Marsha())
}

解析嵌套类型

package main

import (
	"encoding/json"
	"fmt"
)

type Parents []string
type Person struct {
	Name  string
	Age   int
	Email string
	Parents
}

// 解析嵌套类型
func Unmarshal() {
	b := []byte(`{"Name":"tom","Age":20,"Email":"[email protected]", "Parents":["tom", "kite"]}`)
	var f Person
	json.Unmarshal(b, &f)
	fmt.Printf("f: %v\n", f)
}
func main() {
	Unmarshal()
}

忽略字段

如果你想在json 编码/解码 (序列化或反序列化)的时候忽略掉结构体中的某个字段,可以按如下方式在tag中添加-
如果你想在json序列化/反序列化的时候忽略掉结构体中的某个字段,可以按如下方式在tag中添加-

当然,如果你把变量名弄成小写,也是可以实现忽略的效果滴§( ̄▽ ̄

// 使用json tag指定json序列化与反序列化时的行为
type Person struct {
	Name   string `json:"name"` // 指定json序列化/反序列化时使用小写name
	Age    int64
	Weight float64 `json:"-"` // 指定json序列化/反序列化时忽略此字段
}

忽略空值字段

当 struct 中的字段没有值时, json.Marshal() 序列化的时候不会忽略这些字段,而是默认输出字段的类型零值(例如intfloat类型零值是 0,string类型零值是"",对象类型零值是 nil)。如果想要在序列序列化时忽略这些没有值的字段时,可以在对应字段添加omitempty tag。

举个例子:

type User struct {
	Name  string   `json:"name"`
	Email string   `json:"email"`
	Hobby []string `json:"hobby"`
}

func omitemptyDemo() {
	u1 := User{
		Name: "七米",
	}
	// struct -> json string
	b, err := json.Marshal(u1)
	if err != nil {
		fmt.Printf("json.Marshal failed, err:%v\n", err)
		return
	}
	fmt.Printf("str:%s\n", b)
}

输出结果:

str:{"name":"七米","email":"","hobby":null}

如果想要在最终的序列化结果中去掉空值字段,可以像下面这样定义结构体:

// 在tag中添加omitempty忽略空值
// 注意这里 hobby,omitempty 合起来是json tag值,中间用英文逗号分隔
type User struct {
	Name  string   `json:"name"`
	Email string   `json:"email,omitempty"`
	Hobby []string `json:"hobby,omitempty"`
}

此时,再执行上述的omitemptyDemo,输出结果如下:

str:{"name":"七米"} // 序列化结果中没有email和hobby字段

忽略嵌套结构体空值字段

首先来看几种结构体嵌套的示例:

type User struct {
	Name  string   `json:"name"`
	Email string   `json:"email,omitempty"`
	Hobby []string `json:"hobby,omitempty"`
	Profile
}

type Profile struct {
	Website string `json:"site"`
	Slogan  string `json:"slogan"`
}

func nestedStructDemo() {
	u1 := User{
		Name:  "七米",
		Hobby: []string{"足球", "双色球"},
	}
	b, err := json.Marshal(u1)
	if err != nil {
		fmt.Printf("json.Marshal failed, err:%v\n", err)
		return
	}
	fmt.Printf("str:%s\n", b)
}

匿名嵌套Profile时序列化后的json串为单层的:

str:{"name":"七米","hobby":["足球","双色球"],"site":"","slogan":""}

想要变成嵌套的json串,需要改为具名嵌套或定义字段tag:

type User struct {
	Name    string   `json:"name"`
	Email   string   `json:"email,omitempty"`
	Hobby   []string `json:"hobby,omitempty"`
	Profile `json:"profile"`
}
// str:{"name":"七米","hobby":["足球","双色球"],"profile":{"site":"","slogan":""}}

想要在嵌套的结构体为空值时,忽略该字段,仅添加omitempty是不够的:

type User struct {
	Name     string   `json:"name"`
	Email    string   `json:"email,omitempty"`
	Hobby    []string `json:"hobby,omitempty"`
	Profile `json:"profile,omitempty"`
}
// str:{"name":"七米","hobby":["足球","双色球"],"profile":{"site":"","slogan":""}}

还需要使用嵌套的结构体指针:

type User struct {
	Name     string   `json:"name"`
	Email    string   `json:"email,omitempty"`
	Hobby    []string `json:"hobby,omitempty"`
	*Profile `json:"profile,omitempty"`
}
// str:{"name":"七米","hobby":["足球","双色球"]}

不修改原结构体忽略空值字段

我们需要json序列化User,但是不想把密码也序列化,又不想修改User结构体,这个时候我们就可以使用创建另外一个结构体PublicUser匿名嵌套原User,同时指定Password字段为匿名结构体指针类型,并添加omitemptytag,示例代码如下:

type User struct {
	Name     string `json:"name"`
	Password string `json:"password"`
}

type PublicUser struct {
	*User             // 匿名嵌套
	Password *struct{} `json:"password,omitempty"`
}

func omitPasswordDemo() {
	u1 := User{
		Name:     "七米",
		Password: "123456",
	}
	b, err := json.Marshal(PublicUser{User: &u1})
	if err != nil {
		fmt.Printf("json.Marshal u1 failed, err:%v\n", err)
		return
	}
	fmt.Printf("str:%s\n", b)  // str:{"name":"七米"}
}

如果本文帮助到了你,帮我点个广告可以咩(o′┏▽┓`o)


评论
  目录