• Go序列化嵌套结构体



    1. 忽略某个字段

    1. 格式

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

      package main
      
      import (
      	"encoding/json"
      	"fmt"
      )
      
      type Person struct {
      	Name string `json:"name"` // 指定json序列化/反序列化时使用小写name
      	Age  int64
      	Weight float64 `json:"-"` // 指定json序列化/反序列化时忽略此字段
      }
      
      func main() {
      	person := Person{
      		Name: "Jack",
      		Age:  29,
      		Weight: 53.2,
      	}
      
      	p, err := json.Marshal(person)
      	if err != nil {
      		fmt.Printf("json.Marshal failed, err:%v
      ", err)
      		return
      	}
      	fmt.Printf("str:%s
      ", p)
      }
      
    3. 输出

      str:{"name":"Jack","Age":29}
      

    2. 忽略空值字段

    struct 中的字段没有值时,json.Marshal()序列化的时候不会忽略这些字段,而是默认输出字段的类型零值(例如int和float类型零值是 0,string类型零值是"",对象类型零值是 nil)。


    如果想要在序列序列化时忽略这些没有值的字段时,可以在对应字段添加omitempty tag

    1. 示例

      package main
      
      import (
      	"encoding/json"
      	"fmt"
      )
      
      type User struct {
      	Name  string   `json:"name"`
      	Email string   `json:"email"`
      	Hobby []string `json:"hobby"`
      }
      
      func omitemptyDemo() {
      	// 当 struct 中的字段没有值Email,Hobby 字段时
      	u1 := User{
      		Name: "Jack",
      	}
      
      	// struct -> json string
      	b, err := json.Marshal(u1)
      	if err != nil {
      		fmt.Printf("json.Marshal failed, err:%v
      ", err)
      		return
      	}
      	fmt.Printf("str:%s
      ", b)
      }
      
      func main() {
      	omitemptyDemo()
      }
      
      
    2. 输出

      // 结构体没有字段时,会使用结构体字段对应的类型默认值
      str:{"name":"Jack","email":"","hobby":null}
      

    3. 去掉结构体没有字段的值

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

    在对应字段处使用 json, omitempty tag格式忽略不存在的字段值

    1. 格式

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

      package main
      
      import (
      	"encoding/json"
      	"fmt"
      )
      
      type User2 struct {
      	Name  string   `json:"name"`
      	Email string   `json:"email,omitempty"`
      	Hobby []string `json:"hobby,omitempty"`
      }
      
      func omitemptyDemo1() {
      	// 当 struct 中的字段没有值Email,Hobby 字段时
      	u1 := User2{
      		Name: "Jack",
      	}
      
      	// struct -> json string
      	b, err := json.Marshal(u1)
      	if err != nil {
      		fmt.Printf("json.Marshal failed, err:%v
      ", err)
      		return
      	}
      	fmt.Printf("str:%s
      ", b)
      }
      
      func main() {
      	omitemptyDemo1()
      }
      
    3. 输出

      // 输出会将空值忽略掉
      str:{"name":"Jack"}  // 序列化结果中没有email和hobby字段
      

    4. 忽略嵌套结构体空值字段


    4.1 解套结构体解包序列化

    所谓嵌套解包,就是将嵌套的字段以水平展开与原结构体字段合并成一个无嵌套的 json字符串

    1. demo结构如下

      type Profile struct {
      	Website string `json:"site"`
      	Slogan  string `json:"slogan"`
      }
      
      type User struct {
      	Name  string   `json:"name"`
      	Email string   `json:"email,omitempty"`
      	Hobby []string `json:"hobby,omitempty"`
      	Profile             //匿名结构体继承
      }
      
      # 嵌套结构体序列化
      func nestedStructDemo() {
      	// 实例化结构体,缺少嵌套结构体 Profile
      	u1 := User{
      		Name:  "左右逢源",
      		Hobby: []string{"足球", "双色球"},
      	}
      	
      	// 将结构体序列化成 json字符串
      	b, err := json.Marshal(u1)
      	if err != nil {
      		fmt.Printf("json.Marshal failed, err:%v
      ", err)
      		return
      	}
      	fmt.Printf("str:%s
      ", b)
      }
      
    2. 匿名嵌套Profile时序列化后的json串为单层的, 这种序列化会将 嵌套结构体 解包,如下

      str:{"name":"左右逢源","hobby":["足球","双色球"],"site":"","slogan":""}
      

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

    1. 上面的结果并不是我们想要的结果,我们想要的json格式应该如下

       str:{"name":"左右逢源","hobby":["足球","双色球"],"profile":{"site":"","slogan":""}}
      
    2. 嵌套格式如下

      type User struct {
      	Name    string   `json:"name"`
      	Email   string   `json:"email,omitempty"`
      	Hobby   []string `json:"hobby,omitempty"`
      	Profile `json:"profile"`    //嵌套结构体,加上tag 
      }
      // str:{"name":"左右逢源","hobby":["足球","双色球"],"profile":{"site":"","slogan":""}}
      

    4.3 嵌套结构体如果无值,将对应json字段忽略掉

    1. 有的时候我们想在序列化的时候,如果嵌套结构体没有值,那么序列化成json的字段时将该字段忽略掉,这样可以节省内存空间,同时对于api返回也可以防止不必要的返回

       str:{"name":"左右逢源","hobby":["足球","双色球"]} // profile结构体为空时,将此字段忽略掉
      
    2. 格式如下

      type User struct {
      	Name     string   `json:"name"`
      	Email    string   `json:"email,omitempty"`
      	Hobby    []string `json:"hobby,omitempty"`
      	*Profile `json:"profile,omitempty"`   // 使用结构体指针,同时tag加入 omitempty属性表示可以为空
      }
      

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

    1. 比如这样的场景, 用户在调用创建用户接口时,api返回调用结果,需要json序列化User,但是不想把密码也序列化,又不想修改User结构体,这个时就可以使用创建另外一个结构体PublicUser匿名嵌套原User,同时指定Password字段为匿名结构体指针类型,并添加omitemptytag,示例代码如下:

      type User struct {
      	Name     string `json:"name"`
      	Password string `json:"password"`
      }
      
      type PublicUser struct {
      	*User             // 匿名嵌套
      	// 这里相当于将原User结构体中的Password字段覆盖掉了,使用空结构体及tag omitempty强制忽略这个字段
      	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
      ", err)
      		return
      	}
      	
      	fmt.Printf("str:%s
      ", b)  // str:{"name":"左右逢源"}
      }
      
    2. 输出的时候就只有 Name字段被序列化成了 json字符串

       str:{"name":"左右逢源"}
      

    5. 参考

    1. https://zhuanlan.zhihu.com/p/296248435
    ♥永远年轻,永远热泪盈眶♥
  • 相关阅读:
    JAVA_SE基础——59.权限访问修饰符
    JAVA_SE基础——58.如何用jar命令对java工程进行打包
    JAVA_SE基础——57.有了包之后类与类之间的访问使用import语句
    JAVA_SE基础——56.包的创建
    JAVA_SE基础——55.自定义异常类
    JAVA_SE基础——54.异常
    JAVA_SE基础——53.什么是异常?
    Spring整合Mybatis
    Mybatis的ResultMap结果集映射、日志、分页
    Java中的值传递机制
  • 原文地址:https://www.cnblogs.com/failymao/p/15292244.html
Copyright © 2020-2023  润新知