json:",omitempty"json:"-"-json:"-,"
MarshalJSON() ([]byte, error)UnmarshalJSON(b []byte) error

这些都是我们常用的设置技巧。

JSON and struct composition in GoMarshalJSONAlias

以下是译文:

encoding/jsonstrcut
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main
 
import (
"encoding/json"
"os"
"time"
)
 
type MyUser struct {
ID int64 `json:"id"`
Name string `json:"name"`
LastSeen time.Time `json:"lastSeen"`
}
 
func main() {
_ = json.NewEncoder(os.Stdout).Encode(
&MyUser{1, "Ken", time.Now()},
)
}

序列化的结果:

1
{"id":1,"name":"Ken","lastSeen":"2009-11-10T23:00:00Z"}
LastSeen
MarshalJSON
1
2
3
4
5
6
7
8
9
10
11
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中,并让它继承所有不需要改变的字段就太好了:

1
2
3
4
5
6
7
8
9
func (u *MyUser) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
LastSeen int64 `json:"lastSeen"`
*MyUser
}{
LastSeen: u.LastSeen.Unix(),
MyUser: u,
})
}
MarshalJSON

解决办法就是为原始类型起一个别名,别名会有原始struct所有的字段,但是不会继承它的方法:

1
2
3
4
5
6
7
8
9
10
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
}