Go作为强类型语言,在序列化和反序列化过程中,都不可避免地需要定义结构体:在有IDL的情况下结构体可以使用工具自动生成(kitex),在无IDL的情况下就得手撸。
动态JSON字段
代码语言:javascript复制 {
"fields":[
{
"field_name": "名称",
"field_value":"示例文字string类型"
},
{
"field_name": "属性",
"field_value":{
"label":"示例map_key",
"value":"示例map_value"
}
}
]
}
如图所示,fields数组内具体的field_value字段,可能是string
类型,也有可能是map
类型(或者也可以定义为存在Label和Value两个字段的结构体,这里为了更通用化,定义为map[string]string)
如何处理
目前google能得到最好的解决方法参见这篇文章:如何处理动态JSON in Go,结构体最外层专门有一个字段type
标明其他字段类型,然后根据type指示的类型,使用golang提供的type swith语句分别进行处理。type switch语句是go独有的在多个case语句中提供多种类型断言,每种类型分别处理的结果。
这种方法在结合具体业务代码时看上去有些复杂(遍历fields时每次处理都伴随type switch语句)。
本篇博客介绍一种写法更加简单的直接基于类型断言的方法,供golang新手参考。
类型断言
类型断言(Type Assertion)是一个使用在接口值上的操作,用于检查接口类型变量所持有的值是否实现了期望的接口或者具体的类型。
完整的使用方法:
代码语言:javascript复制value, ok := x.(T)
如果变量x
真的是T类型,那么ok
返回true
,否则返回false
,可以再根据ok
的值编写进一步的处理逻辑
实际使用中,如果能确信x
的类型,可以直接写:
value := x.(T)
value
中存储了x
(类型为interface{}
,即任何类型)类型为T
的值。
直接使用类型断言处理动态JSON
首先我们定义field字段为golang中的万用类型interface{}
:
type Fields []Field
type Field struct {
FieldName string `json:"field_name"`
FieldValue interface{} `json:"field_value"`
}
接着在for循环遍历过程中直接使用类型断言转化为具体的类型:
代码语言:javascript复制for _, field := range node.Fields {
if field.FieldName == "名称" {
object[field.FieldName] = field.FieldValue.(string)
} else if field.FieldName == "属性" {
object[field.FieldName] = field.FieldValue.(map[string]interface{})["label"].(string)
}
}