json 潜逃 结构体_go中结构体与json

基本的序列化

Go语言中json.Marshal()(系列化)与json.Unmarshal(反序列化)

隐藏字段相关

忽略空值字段

我们需要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: "like",

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":"like"}

}

忽略某个字段

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

// 使用json tag指定json序列化与反序列化时的行为

type Person struct {

Name string `json:"name"` // 指定json序列化/反序列化时使用小写name

Age int64

Weight float64 `json:"-"` // 指定json序列化/反序列化时忽略此字段

}

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

我们需要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":"七米"}

}

优雅处理字符串格式的数字

有时候,前端在传递来的json数据中可能会使用字符串类型的数字,这个时候可以在结构体tag中添加string来告诉json包从字符串中解析相应字段的数据:

type Card struct {

ID int64 `json:"id,string"` // 添加string tag

Score float64 `json:"score,string"` // 添加string tag

}

func intAndStringDemo() {

jsonStr1 := `{"id": "1234567","score": "88.50"}`

var c1 Card

if err := json.Unmarshal([]byte(jsonStr1), &c1); err != nil {

fmt.Printf("json.Unmarsha jsonStr1 failed, err:%v\n", err)

return

}

fmt.Printf("c1:%#v\n", c1) // c1:main.Card{ID:1234567, Score:88.5}

}

自定义解析时间字段

Go语言内置的 json 包使用 RFC3339 标准中定义的时间格式,对我们序列化时间字段的时候有很多限制。

type Post struct {

CreateTime time.Time `json:"create_time"`

}

func timeFieldDemo() {

p1 := Post{CreateTime: time.Now()}

b, err := json.Marshal(p1)

if err != nil {

fmt.Printf("json.Marshal p1 failed, err:%v\n", err)

return

}

fmt.Printf("str:%s\n", b)

jsonStr := `{"create_time":"2020-04-05 12:25:42"}`

var p2 Post

if err := json.Unmarshal([]byte(jsonStr), &p2); err != nil {

fmt.Printf("json.Unmarshal failed, err:%v\n", err)

return

}

fmt.Printf("p2:%#v\n", p2)

}

上面的代码输出结果如下:

str:{"create_time":"2020-04-05T12:28:06.799214+08:00"}

json.Unmarshal failed, err:parsing time ""2020-04-05 12:25:42"" as ""2006-01-02T15:04:05Z07:00"": cannot parse " 12:25:42"" as "T"

也就是内置的json包不识别我们常用的字符串时间格式,如2020-04-05 12:25:42。

不过我们通过实现 json.Marshaler/json.Unmarshaler 接口实现自定义的事件格式解析。

自定义MarshalJSON和UnmarshalJSON方法

首先你需要知道的是,如果你能够为某个类型实现了MarshalJSON()([]byte, error)和UnmarshalJSON(b []byte) error方法,那么这个类型在序列化(MarshalJSON)/反序列化(UnmarshalJSON)时就会使用你定制的相应方法。

type Order struct {

ID int `json:"id"`

Title string `json:"title"`

CreatedTime time.Time `json:"created_time"`

}

const layout = "2006-01-02 15:04:05"

// MarshalJSON 为Order类型实现自定义的MarshalJSON方法

func (o *Order) MarshalJSON() ([]byte, error) {

type TempOrder Order // 定义与Order字段一致的新类型

return json.Marshal(struct {

CreatedTime string `json:"created_time"`

*TempOrder // 避免直接嵌套Order进入死循环

}{

CreatedTime: o.CreatedTime.Format(layout),

TempOrder: (*TempOrder)(o),

})

}

// UnmarshalJSON 为Order类型实现自定义的UnmarshalJSON方法

func (o *Order) UnmarshalJSON(data []byte) error {

type TempOrder Order // 定义与Order字段一致的新类型

ot := struct {

CreatedTime string `json:"created_time"`

*TempOrder // 避免直接嵌套Order进入死循环

}{

TempOrder: (*TempOrder)(o),

}

if err := json.Unmarshal(data, &ot); err != nil {

return err

}

var err error

o.CreatedTime, err = time.Parse(layout, ot.CreatedTime)

if err != nil {

return err

}

return nil

}

// 自定义序列化方法

func customMethodDemo() {

o1 := Order{

ID: 123456,

Title: "《七米的Go学习笔记》",

CreatedTime: time.Now(),

}

// 通过自定义的MarshalJSON方法实现struct -> json string

b, err := json.Marshal(&o1)

if err != nil {

fmt.Printf("json.Marshal o1 failed, err:%v\n", err)

return

}

fmt.Printf("str:%s\n", b)

// 通过自定义的UnmarshalJSON方法实现json string -> struct

jsonStr := `{"created_time":"2020-04-05 10:18:20","id":123456,"title":"《七米的Go学习笔记》"}`

var o2 Order

if err := json.Unmarshal([]byte(jsonStr), &o2); err != nil {

fmt.Printf("json.Unmarshal failed, err:%v\n", err)

return

}

fmt.Printf("o2:%#v\n", o2)

}

输出结果:

str:{"created_time":"2020-04-05 10:32:20","id":123456,"title":"《七米的Go学习笔记》"}

o2:main.Order{ID:123456, Title:"《七米的Go学习笔记》", CreatedTime:time.Time{wall:0x0, ext:63721678700, loc:(*time.Location)(nil)}}

发布时间:2020-08-03 13:45:37

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值