一、忽略字段
我们知道,通过tag,可以有条件地实现定制Go JSON序列化的方式,比如json:"abc,omitempty"
, 当字段的值为空的时候,我们可以在序列化后的数据中不包含这个值,而json:"-"
可以直接不被JSON序列化,如果想被序列化key-
,可以设置tag为json:"-,"
,加个逗号
二、改变一个字段显示
有下面这个结构体
type MyUser struct {
ID int64 `json:"id"`
Name string `json:"name"`
LastSeen time.Time `json:"lastSeen"`
}
如果临时想改变LastSeen字段显示为时间戳(或者密码我们不想打印到日志中,用***代替)
方案一
最简单的方式是引入另外一个辅助struct,在MarshalJSON
中使用它进行正确的格式化:
func (u *MyUser) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int64 `json:"id"`
Name string `json:"name"`
LastSeen int64 `json:"lastSeen"`
}{
ID: u.ID,
Name: u.Name,
LastSeen: u.LastSeen.Unix(),
})
}
方案二
方案一在遇到多字段的时候会很麻烦,如果我们能把原始struct嵌入到新的struct中,并让它继承所有不需要改变的字段就太好了:
func (u *MyUser) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
LastSeen int64 `json:"lastSeen"`
*MyUser
}{
LastSeen: u.LastSeen.Unix(),
MyUser: u,
})
}
但是,上面这个运行是会有问题的---陷入死循环:辅助struct会继承原始struct的MarshalJSON
解决办法就是为原始类型起个别名,别名会有原始struct所有的字段,但是不会继承它的方法:
func (u *MyUser) MarshalJSON() ([]byte, error) {
type Alias MyUser
return json.Marshal(&struct {
LastSeen int64 `json:"lastSeen"`
*Alias
}{
LastSeen: u.LastSeen.Unix(),
Alias: (*Alias)(u),
})
}
同样的技术也可以应用于UnmarshalJSON
方法:
func (u *MyUser) UnmarshalJSON(data []byte) error {
type Alias MyUser
aux := &struct {
LastSeen int64 `json:"lastSeen"`
*Alias
}{
Alias: (*Alias)(u),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
u.LastSeen = time.Unix(aux.LastSeen, 0)
return nil
}
三、使用 json.RawMessage
如果部分json文档没有标准格式,我们可以把原始的文本信息用string保存下来。
type TestObject struct {
Field1 string
Field2 json.RawMessage
}
var data TestObject
json.Unmarshal([]byte(`{"field1": "hello", "field2": [1,2,3]}`), &data)
should.Equal(` [1,2,3]`, string(data.Field2))
后续可以继续对Filed2
调用Unmarshal
四、使用 json.Number
默认情况下,如果是 interface{} 对应数字的情况会是 float64 类型的。如果输入的数字比较大,这个表示会有损精度。所以可以 UseNumber() 启用 json.Number 来用字符串表示数字。
// 字符串中author字段不确定是string还是uint64时
type Record struct {
AuthorRaw interface{} `json:"author"`
Title string `json:"title"`
URL string `json:"url"`
AuthorEmail string
AuthorID uint64
}
func Decode(r io.Reader) (x *Record, err error) {
x = new(Record)
if err = json.NewDecoder(r).Decode(x); err != nil {
return
}
switch t := x.AuthorRaw.(type) {
case string:
x.AuthorEmail = t
case json.Number:
var n uint64
// We would shadow the outer `err` here by using `:=`
n, err = t.Int64()
x.AuthorID = n
}
return
}
当然,这里用json.RawMessage
也是可以的。
五、一个json切分成两个struct
json.Unmarshal([]byte(`{
"url": "attila@attilaolah.eu",
"title": "Attila's Blog",
"visitors": 6,
"page_views": 14
}`), &struct {
*BlogPost
*Analytics
}{&post, &analytics})
网友评论