赞
踩
以下内容转载自 https://blog.csdn.net/changqi008/article/details/105471250
结构体转map[string]interface{}
- // UserInfo 用户信息
- type UserInfo struct {
- Name string `json:"name"`
- Age int `json:"age"`
- }
-
- u1 := UserInfo{Name: "奇奇", Age: 18}
将此结构体转成map[string]interface{}JSON反序列化
- func main() {
- u1 := UserInfo{Name: "奇奇", 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)
- }
- }
看到的结果是:
- key:name value:奇奇
- key:age value:18
看起来好像没有什么问题,但是,当我们看他们的类型的时候你就会发现有不一样的地方了
我们来验证下
- func main() {
- u1 := UserInfo{Name: "奇奇", 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 value type:%T\n", k, v, v)
- }
- }
再来看下结果
- key:name value:奇奇 value type:string
- key:age value:18 value type:float64
可以看出age的类型明明是int型的,转成map之后就变成了float64类型了呢?
原因是:
在JSON协议中没有整型和浮点型之分,它们统称为Number,json字符串中的数组经过go语言中的json经过反序列化之后都会成为float64,但是我们也有办法在转成int型,就是先要将得到的float64经过序列化之后得到json.number类型之后,在转为int类型.
反射
除了上面说到的方法之外,我们还有利用反射遍历结构体的方式生成map
- // 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
- }
对此可以验证下
- m2, _ := ToMap(&u1, "json")
- for k, v := range m2{
- fmt.Printf("key:%v value:%v value type:%T\n", k, v, v)
- }
可以看到输出的结果为:
- key:name value:奇奇 value type:string
- key:age value:18 value type:int
第三方库structs
除了上述自己实现的以外,在github上面也有一些实现好了的轮子,比如:https://github.com/fatih/structs
它使用的是自定义结构体:struts
- // UserInfo 用户信息
- type UserInfo struct {
- Name string `json:"name" structs:"name"`
- Age int `json:"age" structs:"age"`
- }
用法是:
- m3 := structs.Map(&u1)
- for k, v := range m3 {
- fmt.Printf("key:%v value:%v value type:%T\n", k, v, v)
- }
是的,是不是方便很多,在这个包中还有其他方法,可以查看文档,据说被作者设置成只读模式
- // UserInfo 用户信息
- type UserInfo struct {
- Name string `json:"name" structs:"name"`
- Age int `json:"age" structs:"age"`
- Profile `json:"profile" structs:"profile"`
- }
-
- // Profile 配置信息
- type Profile struct {
- Hobby string `json:"hobby" structs:"hobby"`
- }
申明结构体变了u1 u1 := UserInfo{Name: "奇奇", Age: 18, Profile: Profile{"双色球"}}
- m3 := structs.Map(&u1)
- for k, v := range m3 {
- fmt.Printf("key:%v value:%v value type:%T\n", k, v, v)
- }
输出结果: - key:name value:奇奇 value type:string
- key:age value:18 value type:int
- key:profile value:map[hobby:双色球] value type:map[string]interface {}
从结果来看最后嵌套字段profile是map[string]interface {},属于map嵌套map。- // ToMap2 将结构体转为单层map
- func ToMap2(in interface{}, tag string) (map[string]interface{}, error) {
-
- // 当前函数只接收struct类型
- 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)
- }
-
- out := make(map[string]interface{})
- queue := make([]interface{}, 0, 1)
- queue = append(queue, in)
-
- for len(queue) > 0 {
- v := reflect.ValueOf(queue[0])
- if v.Kind() == reflect.Ptr { // 结构体指针
- v = v.Elem()
- }
- queue = queue[1:]
- t := v.Type()
- for i := 0; i < v.NumField(); i++ {
- vi := v.Field(i)
- if vi.Kind() == reflect.Ptr { // 内嵌指针
- vi = vi.Elem()
- if vi.Kind() == reflect.Struct { // 结构体
- queue = append(queue, vi.Interface())
- } else {
- ti := t.Field(i)
- if tagValue := ti.Tag.Get(tag); tagValue != "" {
- // 存入map
- out[tagValue] = vi.Interface()
- }
- }
- break
- }
- if vi.Kind() == reflect.Struct { // 内嵌结构体
- queue = append(queue, vi.Interface())
- break
- }
- // 一般字段
- ti := t.Field(i)
- if tagValue := ti.Tag.Get(tag); tagValue != "" {
- // 存入map
- out[tagValue] = vi.Interface()
- }
- }
- }
- return out, nil
- }
测试一下: - m4, _ := ToMap2(&u1, "json")
- for k, v := range m4 {
- fmt.Printf("key:%v value:%v value type:%T\n", k, v, v)
- }
输出: - key:name value:奇奇 value type:string
- key:age value:18 value type:int
- key:hobby value:双色球 value type:string
这下我们就把嵌套的结构体转为单层的map了,但是要注意这种场景下结构体和嵌套结构体的字段就需要避免重复。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。