修改序列化后的 Key 值

 type User struct {
     ID int `json:"id"`
     Name string `json:"name"`
 }

 // output
 {"id": 12, "name": "laily"}

数字转字符串

前端 js 对 int64 的处理可能会因为溢出导致无法准确处理,因此我们期望可以返回字符串类型。

 type User struct {
     ID int64 `json:"id,string"`
 }

 // output
 {"id":"123131"}

忽略零值

 type User struct {
     ID int `json:"id,omitempty"`
     Name string `json:"name,omitempty"`
 }

如果 ID 是 0,Name 是空字符串则在序列化的结果里不会有这两个 key。

强制忽略某些 key

 type User struct {
     ID int `json:"id"`
     Name string `json:"-"`
 }

无论 Name 是什么值,序列化后都没有这个 key。

定制 Marshaler/Unmarshal

 type ID int64
 func (i ID) MarshalJSON() ([]byte, error) {
         if i < 0 {
             return nil, xerrors.Errorf("err: ID(%d) must greater than 0", i)
         }
         str, err := seed.EncodeInt64([]int64{int64(i)})
         if err != nil {
             return nil, err
         }
         return []byte(str), nil
 }

 func (i *ID) UnmarshalJSON(data []byte) error {
         is, err := seed.DecodeInt64WithError(string(data))
         if err != nil {
             return xerrors.Errorf("unmarshal id failed, %w", err)
         }
         if len(is) != 1 {
             return xerrors.Errorf("bad unmarshal id length, %d", len(is))
         }
         *i = ID(is[0])
         return nil
 }

懒惰解析/编码

有些时候我们无法一下确定需要解析的内容,可能需要先解析一部分字段,比如 type,然后才能知道另一个字段 content 的结构。这种情况下可以把 content 这个动态的结构先定义为 json.RawMessage 这个类型。

 type Message struct {
         MessageType  MessageType     `json:"messageType"`
         MessageId    int64           `json:"messageId"`
         Payload      json.RawMessage `json:"payload"`
 }

如上,我们可以这样定义结构,先解析为 Message,然后根据 MessageType 准备另一个结构体去再解析一次 Payload。

 m := &Message{}
 err := json.Unmarshal(data, m)
 if m.MessageType == "A"{
     payloadA := &PayloadTypeA{}
     json.Unmarshal(m.Payload, payloadA)
 }else if m.MessageType == "B"{
     payloadB := &PayloadTypeB{}
     json.Unmarshal(m.Payload, payloadB)
 }

保留长整形

默认的 json 实现中,如果一个数据是长整型,并且对应的 go 中的数据类型是 interface 的话,就会产生解析成 float64 的问题,这个是绝对不能接受的。可以通过如下办法来解决:

 d := json.NewDecoder(strings.NewReader(`{"a": 1234567890987654321}`))
 res1 := make(map[string]interface{})
 d.Decode(&res1)
 fmt.Printf("%+v, type: %s\n", res1, reflect.TypeOf(res1["a"]))

 d = json.NewDecoder(strings.NewReader(`{"a": 1234567890987654321}`))
 d.UseNumber()
 res := make(map[string]interface{})
 d.Decode(&res)
 fmt.Printf("%+v, type: %s\n", res, reflect.TypeOf(res["a"]))
 
 // output
 // map[a:1.2345678909876544e+18], type: float64
 // map[a:1234567890987654321], type: json.Number

参考

https://zhuanlan.zhihu.com/p/97374956