Go json Marshal & UnMarshal 的一点小 trick

在编写 Web Service 等涉及数据序列化和反序列化的场景,对于 JSON 类型的数据,在 Go 中我们经常会使用到 encoding/json Package。最近微有所感,小水一篇

omitempty

JSON 数据的 UnMarshal 我们经常会配合 Struct Tags 使用,让 Struct 的 Filed 与 JSON 数据的指定 property 绑定。

如果要序列化为 Go Struct 的 JSON 数据对应的 Fields 相关的 JSON properties 是缺失的,我们经常会用 omitempty 标记 Go Fields,序列化时,JSON 数据中缺少的属性将会被设置为 Go 中对应的 zero-value,比如:

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name string `json:"name"`
    Age  string `json:"age,omitempty"`
    Weak bool   `json:"weak,omitempty"`
}

func main() {
    jsonData := `{"name":"ShanSan"}`
    req := Person{}
    _ = json.Unmarshal([]byte(jsonData), &req)
    fmt.Printf("%+v", req)
    fmt.Println(req.Age)
}
// output
// {Name:ShanSan Age: Weak:false}
//

Go Playground Link

但上面的例子对于一些场景的处理可能会有问题。看下下面这个例子:

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name string `json:"name"`
    Age  string `json:"age,omitempty"`
    Weak bool   `json:"weak,omitempty"`
}

func main() {
    jsonData := `{"name":"ShanSan", "age": ""}`
    req := Person{}
    _ = json.Unmarshal([]byte(jsonData), &req)
    fmt.Printf("%+v", req)
    fmt.Println(req.Age)
}
// output
// {Name:ShanSan Age: Weak:false}
//

可以看到 age 为 "" 时,和缺省时的结果是一样的。很显然,上面的写法,缺省的字段和空字段是没有被区分开的。对于一些数据的 Update 操作,比如我们只想 Update Name 字段,对应的 JSON 数据为 {"name":"ShanSan"},执行上述的反序列化动作,Age 字段会被设置为 empty string,Waek 也被设置为了 false,这显然不是我们想看到的。

nil 一下

我们可以指针类型(pointer type)对上面的情况区分一下:

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name *string `json:"name"`
    Age  *string `json:"age,omitempty"`
    Weak *bool   `json:"weak,omitempty"`
}

func main() {
    jsonData := `{"name":"ShanSan"}`
    jsonDataEmptyAge := `{"name":"ShanSan", "age": ""}`
    req := Person{}
    reqEmptyAge := Person{}
    _ = json.Unmarshal([]byte(jsonData), &req)
    _ = json.Unmarshal([]byte(jsonDataEmptyAge), &reqEmptyAge)
    fmt.Printf("%+v", req)
    fmt.Printf("%+v", reqEmptyAge)
}
// {Name:0xc000010390 Age:<nil> Weak:<nil>}{Name:0xc0000103c0 Age:0xc0000103d0 Weak:<nil>}

emmm,缺省的字段为 nil 了。

Marshal 的时候

序列化 struct 的时候,如果使用了 omitempty,也会出现类似上面反序列化的情况,对于缺省的 field 或者 zero-value,序列化得到的 JSON 数据也会缺省相关属性,此时我们也可以通过 pointer 保留相关字段,如下:

package main

import (
    "encoding/json"
    "fmt"
)

type Student struct {
    Name  string `json:"name"`
    Score int    `json:"score,omitempty"`
}

type StudentWithPointer struct {
    Name  string `json:"name"`
    Score *int   `json:"score,omitempty"`
}

func main() {
    student := Student{
        Name:  "ShanSan",
        Score: 0,
    }

    score := 0
    studentWithPointer := StudentWithPointer{
        Name:  "ShanSan",
        Score: &score,
    }

    data, _ := json.Marshal(student)
    dataWithPointer, _ := json.Marshal(studentWithPointer)
    fmt.Println(string(data))
    fmt.Println(string(dataWithPointer))
}
// {"name":"ShanSan"}
// {"name":"ShanSan","score":0}

Go Playground

参考

本文由博客群发一文多发等运营工具平台 OpenWrite 发布

  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yeshan333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值