后端开发人员跟前端对接接口的时候,或多或少都会面临一些沟通问题,比如说枚举字符的定义,比如有整形状态字段:state
1: 成功
2: 失败
3: 处理中
通常给前端的时候,前段要做的是将1,2,3以及对应的中文释义存储为key/value的形式,key与value单看都无法知道对方的语义,
比如我只知道状态值为“1”, 是无法将其与“成功”对应起来的(当然这套状态的设计者肯定是知道的),后端通常给到前端的restful api
接口定义也是key/value的形式,这乍一看其实也没啥毛病,只要有key/value也没问题,后端定义通常会是
type MyResponse struct {
ID int64 `json:"id"`
State int `json:"state"`
}
但数字的表现形式终归是不不太明确的,如果对状态的定义换成以下形式:
Success: 成功
Fail: 失败
Pending: 处理中
基本可以理解为中英文互译了,理解起来也会更清晰一些不是,如果这么做的话,后端给到前端的响应字段状态的类型就需要修改成字符器格式
type MyResponse struct {
ID int64 `json:"id"`
State string `json:"state"`
}
后端还是要做一层字符串到整型的转换,从目的来讲,我们只是想返给前端的state
字段是字符串而已,也就是在做json序列化的时候将整型与字符串做一层转换,有更优雅的做法如下所示
type MyState int
func (u MyState) MarshalJSON() ([]byte, error) {
var buf bytes.Buffer
switch u {
case 1:
_, err := buf.WriteString(`"Success"`)
return buf.Bytes(), err
case 2:
_, err := buf.WriteString(`"Fail"`)
return buf.Bytes(), err
case 3:
_, err := buf.WriteString(`"Pending"`)
return buf.Bytes(), err
}
return nil, fmt.Errorf("unsupported value: %v!", u)
}
只需要做两件事,自定义类型MyState
,实现MarshalJSON
方法
// Marshaler is the interface implemented by types that
// can marshal themselves into valid JSON.
type Marshaler interface {
MarshalJSON() ([]byte, error)
}
只要类型实现了MarshalJSON
方法,在json序列化时就会调用此方法,如此一来,我们就轻松实现了自定义json序列化,反序列化同样如此
// Unmarshaler is the interface implemented by types
// that can unmarshal a JSON description of themselves.
// The input can be assumed to be a valid encoding of
// a JSON value. UnmarshalJSON must copy the JSON data
// if it wishes to retain the data after returning.
//
// By convention, to approximate the behavior of Unmarshal itself,
// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op.
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
实现起来也很简单
func (u *MyState) UnmarshalJSON(data []byte) error {
switch string(data) {
case `"Success"`:
*u = 1
return nil
case `"Fail"`:
*u = 2
return nil
case `"Pending"`:
*u = 3
return nil
}
return fmt.Errorf("unsupported value: %v!", *u)
}
需要注意的是,UnmarshalJSON
方法操作过程需要给receiver
也就是u
赋值,所以必须是指针类型,同样的,在实现
MarshalJSON
方法,receiver
的类型需要与结构体定义中的类型保持一致,否则自定义序列化会失败
参考:
- https://golang.org/src/encoding/json/encode.go?s=6458:6501#L222
- https://golang.org/src/encoding/json/decode.go?s=4787:4846#L109
有疑问加站长微信联系(非本文作者)