携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第18天,点击查看活动详情
前言
json格式可以算我们日常最常用的序列化格式之一了,虽然golang对json格式支持很好,但是对json序列化和反序列化的操作实在是难受,所以说用习惯了高级语言特性,再转到这些偏原生的写法上就会很难受。经常遇到一些问题诸如字段类型变化导致无法正常解析的情况,导致服务不稳定。本文主要总结一下日常我们开发中对json的使用总结,需要的朋友可以参考以下内容,希望对大家有帮助。
基本的使用
go的json解析需要使用encoding/json包
- 序列化,也就是由结构体转化为json string字符串。使用json.Marshal函数。
- 反序列化,就是将json string字符串转化为结构体。使用函数json.Unmarshal函数完成。
首先我们来看一下Go语言中序列化json.Marshal()与反序列化json.Unmarshal()的基本用法。
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string
Age int
}
func main(){
var user1 = User{
Name:"张三",
Age:18,
}
//json序列化
jsons, err := json.Marshal(user1)
if err != nil {
fmt.Println("json Marshal error:", err)
return
}
fmt.Printf("user1 jsons:%s\n", jsons)//user1 jsons:{"Name":"张三","Age":18}
var user2 User
//json返序列化
err = json.Unmarshal(jsons, &user2)
if err != nil {
fmt.Println("json Unmarshal error:", err)
return
}
fmt.Println(user2) //{张三 18}
}
注意:
结构体的字段首字母要大写。如果json字符串首字母都是小写怎么办?后面会说tag的使用。
Tag的使用
何为Tag,tag就是标签,给结构体的每个字段打上一个标签,标签冒号前是类型,后面是标签名。格式如下:
`key1:"value1" key2:"value2"
结构体tag由一个或多个键值对组成。键与值使用冒号分隔,值用双引号括起来。同一个结构体字段可以设置多个键值对tag,不同的键值对之间使用空格分隔。
使用json tag指定字段名
序列化与反序列化默认情况下使用结构体的字段名,我们可以通过给结构体字段添加tag来指定json序列化生成的字段名:
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Sex string `json:"gender"`
}
func main(){
var user1 = User{
Name:"张三",
Age:18,
Sex:"男",
}
//json序列化
jsons, err := json.Marshal(user1)
if err != nil {
fmt.Println("json Marshal error:", err)
return
}
fmt.Printf("user1 jsons:%s\n", jsons)//user1 jsons:{"name":"张三","age":18,"gender":"男"}
}
忽略某个字段
如果你想在json序列化/反序列化的时候忽略掉结构体中的某个字段,可以按如下方式在tag中添加-。
// 使用json tag指定json序列化与反序列化时的行为
type User struct {
Name string `json:"name"` // 指定json序列化/反序列化时使用小写name
Age int
Sex string `json:"-"` // 指定json序列化/反序列化时忽略此字段
}
忽略空值字段
当 struct 中的字段没有值时, json.Marshal() 序列化的时候不会忽略这些字段,而是默认输出字段的类型零值(例如int和float类型零值是 0,string类型零值是"",对象类型零值是 nil)。如果想要在序列序列化时忽略这些没有值的字段时,可以在对应字段添加omitempty tag。
package main
import (
"encoding/json"
"fmt"
)
// 在tag中添加omitempty忽略空值
// 注意这里 age,omitempty 合起来是json tag值,中间用英文逗号分隔
type User struct {
Name string `json:"name"`
Age int `json:"age,omitempty"`
Sex string `json:"gender,omitempty"`
}
func main(){
var user1 = User{
Name:"张三",
}
//json序列化
jsons, err := json.Marshal(user1)
if err != nil {
fmt.Println("json Marshal error:", err)
return
}
fmt.Printf("user1 jsons:%s\n", jsons)//user1 jsons:{"Name":"张三"}
}
忽略嵌套结构体空值字段
package main
import (
"encoding/json"
"fmt"
)
type Hobby struct {
Like string `json:"like"`
}
type User struct {
Name string `json:"name"`
Age int `json:"age,omitempty"`
Sex string `json:"gender,omitempty"`
Hobby
}
func main(){
var user1 = User{
Name:"张三",
Hobby:Hobby{
Like:"足球",
},
}
//json序列化
jsons, err := json.Marshal(user1)
if err != nil {
fmt.Println("json Marshal error:", err)
return
}
fmt.Printf("user1 jsons:%s\n", jsons)
}
匿名嵌套Hobby时序列化后的json串为单层的:
user1 jsons:{"name":"张三","like":"足球"}
想要变成嵌套的json串,需要改为具名嵌套或定义字段tag:
type User struct {
Name string `json:"name"`
Age int `json:"age,omitempty"`
Sex string `json:"gender,omitempty"`
Hobby `json:"hobby"`
}
//user1 jsons:{"name":"张三","hobby":{"like":"足球"}}
想要在嵌套的结构体为空值时,忽略该字段,仅添加omitempty是不够的,还需要使用嵌套的结构体指针:
type User struct {
Name string `json:"name"`
Age int `json:"age,omitempty"`
Sex string `json:"gender,omitempty"`
*Hobby `json:"hobby,omitempty"` //需要使用嵌套的结构体指针
}
//user1 jsons:{"name":"张三"}
总结
以上就是我们在开发中josn序列化经常用到的和遇到的一些情况,需要的朋友可以参考,希望对你有帮助。