结构体转 map[string]interface{} 的若干方法
本文介绍了Go语言中将结构体转成 map[string]interface{}
时你需要了解的“坑”,也有你需要知道的若干方法。
我们在Go语言中通常使用结构体来保存我们的数据,例如要存储用户信息,我们可能会定义如下结构体:
Go |
---|
| // UserInfo 用户信息
type UserInfo struct {
Name string `json:"name"`
Age int `json:"age"`
}
u1 := UserInfo{Name: "q1mi", Age: 18}
|
假设现在要将上面的 u1
转换成 map[string]interface{}
,该如何操作呢?
JSON序列化方式
Go |
---|
| func main() {
u1 := UserInfo{Name: "q1mi", Age: 18}
b, _ := json.Marshal(&u1)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m{
fmt.Printf("key:%v value:%v\n", k, v)
}
}
|
看起来没什么问题,但其实这里是有一个“坑”的。那就是Go语言中的 json
包在序列化空接口存放的数字类型(整型、浮点型等)都会序列化成 float64
类型。很显然,出现了一个意料之外的行为,我们需要想办法规避掉。
反射
这里使用反射遍历结构体字段的方式生成 map,具体代码如下:
Go |
---|
| // ToMap 结构体转为Map[string]interface{}
func ToMap(in interface{}, tagName string) (map[string]interface{}, error){
out := make(map[string]interface{})
v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct { // 非结构体返回错误提示
return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v)
}
t := v.Type()
// 遍历结构体字段
// 指定tagName值为map中key;字段值为map中value
for i := 0; i < v.NumField(); i++ {
fi := t.Field(i)
if tagValue := fi.Tag.Get(tagName); tagValue != "" {
out[tagValue] = v.Field(i).Interface()
}
}
return out, nil
}
|