事件背景
Golang 因为是编译性的语言,导致在 JSON 反序列化的时候会有很多的不方便。尤其是对于 golang 调用 java 或者 nodejs 开发的服务的时候,返回结果的结构复杂,嵌到层级深的情况,就变得非常难搞。
主要挑战如下:
- golang 需要写大量 struct 去应对上游服务返回的数据结构
- 由于数据结构是项目代码的一部分,导致需要跟随上游数据结构变化,不停编译和发布,非常合理
- 时间宝贵,心智负担很重,稍微遗漏一点,就解析不成功,就要花费大量时间去解析
常用手段
使用 map[string]interface{} 来接收数据格式,但是最后你得到的是一个 map ,而不是你要的 struct。 如何在 interface{} 和 struct 之间获得最少代码,最好的适应性,要什么数据就取哪里的数据,岂不“逍遥自在”。
解决方案
这里就不多啰嗦了,直接上 demo 代码。有很多注解,很好理解。
package main
import (
"encoding/json"
"log"
)
type Object struct {
Something interface{} `json:"something"`
}
type File struct {
FileName string `json:"file_name"`
}
func main() {
// 输入数据流
input := `
{
"something": {
"file_name": "for test"
}
}
`
// 定义需要 "延迟解析" 的json 字符串
var object json.RawMessage
// 创建一个对象,将 interface{} 字段内容保存到对应 RawMessage 对象中
o := Object{Something: &object}
// 第一次反序列化,已经延迟解析了
if err := json.Unmarshal([]byte(input), &o); err != nil {
log.Println(">>>>>>>>>> 1.", err)
return
}
// 定义 "延迟解析" 的接收对象
var f File
// 第二次进行解析,因为第二次解析才真正去解析第一次延迟未解析的内容
if err := json.Unmarshal(object, &f); err != nil {
log.Println(">>>>>>>>>> 2.", err)
return
}
log.Println("Result", f.FileName)
}
执行结果
2022/01/13 15:29:23 Result for test