我写的接口,基本长这样:
{
"code": 200,
"msg": "原因",
"result": {} // 或者空或者其它
}
所以在Go里,定义如下:
type Resp struct {
Code int `json:"code"`
Msg string `json:"msg"`
Result interface{} `json:"result"`
}
然后,在返回值时,就可以定义好结构,比如:
type UserResult struct {
UserID int `json:"user_id"`
}
result
func bodyToStruct(byteArray []byte, s interface{}) {
err := json.Unmarshal(byteArray, &s)
if err != nil {
log.Printf("failed to unmarshal %s: %s", byteArray, err)
}
}
这是一个把 []byte 转换成对应结构体的帮助函数,不过,result是不好转的,一开始我有尝试这样:
resp := Resp{Result: UserResult{}}
ResultResult
func resultToStruct(result, s interface{}) {
byteArray, err := json.Marshal(result)
if err != nil {
logrus.Errorf("failed to marshal %s: %s", result, err)
return
}
err = json.Unmarshal(byteArray, s)
if err != nil {
logrus.Errorf("failed to unmarshal %s: %s", byteArray, err)
return
}
}
很明显,有点low,转来转去。经过群友的提醒,是我最上面应该传指针,于是改成这样就可以了:
resp := Resp{Result: &Result}
bodyToStructresp.Result.UserIDResp.Resultinterface{}
resp := Resp{}
result := Result{}
resp.Result = &result
bodyToStruct(bytes, &resp)
于是就可以了。看看demo代码:
package main
import (
"encoding/json"
"log"
)
type Resp struct {
Code int `json:"code"`
Msg string `json:"msg"`
Result interface{} `json:"result"`
}
type UserResult struct {
UserID int `json:"user_id"`
}
func bodyToStruct(byteArray []byte, s interface{}) {
err := json.Unmarshal(byteArray, &s)
if err != nil {
log.Printf("failed to unmarshal %s: %s", byteArray, err)
}
}
func main() {
byteArray := []byte(`{"code":200,"msg":"","result":{"user_id": 1}}`)
resp := Resp{}
result := UserResult{}
resp.Result = &result
bodyToStruct(byteArray, &resp)
log.Printf("user id is %d", result.UserID)
}
于是,就终于可以愉快的类型安全的使用返回值了。这样做有几个好处:
- 类型安全
- 可以复用定义接口时写的struct
- 可以补全
有同学可能认为,为啥不直接用interface,断言?嗯,其实我曾经年少轻狂的时候,经常说我是interface走天下,直到我的程序不断的 崩崩崩,我才老老实实重新做人,老老实实的类型安全。
这就是这次想要分享的技巧。