1. 忽略某个字段
go
type Person struct {
Name string `json:"name"` // 指定json序列化/反序列化时使用小写name
Age int64
Weight float64 `json:"-"` // 指定json序列化/反序列化时忽略此字段
}
2. 忽略空值字段
go
// 在tag中添加omitempty忽略空值
// 注意这里hobby,omitempty合起来是json tag值,中间用英文逗号分隔
type Person struct {
Name string `json:"name"`
Age int64
Weight float64 `json:"hobby,omitempty"`
}
3. 嵌套匿名结构体
匿名嵌套 Login 时序列化后的 json 串为单层
go
type User struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
Login
}
type Login struct {
Account string `json:"account"`
Password string `json:"password"`
}
func main() {
u := User{
Name: "小王子",
}
b, err := json.Marshal(u)
if err != nil {
fmt.Printf("json.Marshal failed, err:%v\n", err)
return
}
fmt.Printf("%s\n", b) // {"name":"小王子","account":"","password":""}
}
想要变成嵌套的 json 串,需要改为具名嵌套或定义字段 tag:
lua
type User struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
Login `json:"login"`
}
type Login struct {
Account string `json:"account"`
Password string `json:"password"`
}
// {"name":"小王子","login":{"account":"","password":""}}
想要在嵌套的结构体为空值时,忽略该字段,仅添加 omitempty 是不够的:
lua
type User struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
Login `json:"login,omitempty"`
}
// {"name":"小王子","login":{"account":"","password":""}}
还需要使用嵌套的结构体指针:
go
type User struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
*Login `json:"login,omitempty"`
}
// {"name":"小王子"}
4. 不修改原结构体忽略某个字段
go
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
type UserOmitEmail struct {
*User
Email *struct{} `json:"email,omitempty"`
}
func main() {
u := User{
Name: "小王子",
Email: "APTX4869",
}
u2 := UserOmitEmail{User: &u}
b, err := json.Marshal(u2)
if err != nil {
fmt.Printf("json.Marshal failed, err:%v\n", err)
return
}
fmt.Printf("%s\n", b) // {"name":"小王子"}
}
5. 处理字符串格式的数字
有时候,前端在传递来的 json 数据中可能会使用字符串类型的数字,这个时候可以在结构体 tag 中添加 string 来告诉 json 包从字符串中解析相应字段的数据:
go
type Card struct {
ID int64 `json:"id,string"` // 添加string tag
Scope float64 `json:"scope,string"` // 添加string tag
}
func main() {
jsonStr := `{"id": "1234567","scope": "88.50"}`
var c Card
if err := json.Unmarshal([]byte(jsonStr), &c); err != nil {
fmt.Printf("json.Unmarsha jsonStr failed, err:%v\n", err)
return
}
fmt.Printf("%+v\n", c) // {ID:1234567 Scope:88.5}
}
6. 整型变浮点型
将 JSON 中的数字解码为 interface 类型 to unmarshal JSON into an interface value 之后会成为 float64 类型。
go
func main() {
var data = []byte(`{"status": 200}`)
var result map[string]interface{}
if err := json.Unmarshal(data, &result); err != nil {
log.Fatalln(err)
}
fmt.Printf("%T\n", result["status"]) // float64
}
因为使用的类型是空接口:interface{},在 json 包有解释,interface{} 在 json unmarshal 时,如果 json 数据为 number 类型,则会使用 float64
arduino
// To unmarshal JSON into an interface value,
// Unmarshal stores one of these in the interface value:
//
// bool, for JSON booleans
// float64, for JSON numbers
// string, for JSON strings
// []interface{}, for JSON arrays
// map[string]interface{}, for JSON objects
// nil for JSON null
7. 使用匿名结构体添加字段
使用内嵌结构体能够扩展结构体的字段,但有时候我们没有必要单独定义新的结构体,可以使用匿名结构体简化操作:
go
type User struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
}
func main() {
u := User{
Name: "小王子",
}
b, err := json.Marshal(struct {
*User
Account string `json:"account"`
}{
&u,
"12138",
})
if err != nil {
fmt.Printf("json.Marshal failed, err:%v\n", err)
return
}
fmt.Printf("%s\n", b) // {"name":"小王子","account":"12138"}
}
8. 可以使用 struct 将数值类型映射为 json.RawMessage 原生数据类型
css
// 状态名称可能是 int 也可能是 string,指定为 json.RawMessage 类型
func main() {
records := [][]byte{
[]byte(`{"status":200, "tag":"one"}`),
[]byte(`{"status":"ok", "tag":"two"}`),
}
for idx, record := range records {
var result struct {
StatusCode uint64
StatusName string
Status json.RawMessage `json:"status"`
Tag string `json:"tag"`
}
if err := json.NewDecoder(bytes.NewReader(record)).Decode(&result); err != nil{
log.Fatal(err)
}
var name string
err := json.Unmarshal(result.Status, &name)
if err == nil {
result.StatusName = name
}
var code uint64
err = json.Unmarshal(result.Status, &code)
if err == nil {
result.StatusCode = code
}
fmt.Printf("[%v] result => %+v\n", idx, result)
}
}
9. omitempty 忽略空值,但是已经赋值为0值情况下不忽略,需传该字段指针类型
css
type Student struct {
Name string `json:"name"`
Age *int `json:"age,omitempty"`
}
func main() {
stu1 := Student{
Name: "Tom",
}
a := 0
stu2 := Student{
Name: "LiLy",
Age: &a,
}
b1, _ := json.Marshal(&stu1)
b2, _ := json.Marshal(&stu2)
fmt.Println("stu1:", string(b1))
fmt.Println("stu2:", string(b2))
}
// stu1: {"name":"Tom"}
// stu2: {"name":"LiLy","age":0}
10. json marshal json string 时的转义问题
go
func main() {
s, err := marshalResponse(0, "ok", `{"name": "tony", "city": "shenyang"}`)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(s)
}
func marshalResponse(code int, msg string, result interface{}) (string, error) {
m := map[string]interface{}{
"code": code,
"msg": msg,
"result": result,
}
b, err := json.Marshal(&m)
if err != nil {
return "", err
}
return string(b), nil
}
输出:
ruby
{"code":0,"msg":"ok","result":"{"name": "tony", "city": "shenyang"}"}
输出带有转义反斜线,怎么解决掉这个问题呢?json 提供了一种 RawMessage 类型,本质上就是 []byte,我们将json string 转换成 RawMessage 后再传给 json.Marshal 就可以解决掉这个问题了。
go
func main() {
s, err := marshalResponse(0, "ok", `{"name": "tony", "city": "shenyang"}`)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(s)
}
func marshalResponse(code int, msg string, result interface{}) (string, error) {
m := map[string]interface{}{
"code": code,
"msg": msg,
}
s, ok := result.(string)
if ok {
rawData := json.RawMessage(s)
m["result"] = rawData
} else {
m["result"] = result
}
b, err := json.Marshal(&m)
if err != nil {
return "", err
}
return string(b), nil
}
输出:
css
{"code":0,"msg":"ok","result":{"name":"tony","city":"shenyang"}}