Golang实现优雅的将struct转换为map
劲仔Go 人气:0前言
在项目实践中,有时候我们需要将struct结构体转为map映射表,然后基于map做数据裁剪或操作。那么下面我来介绍下常用的两种转换方式,以及对它们做对比,最后采用更优雅的方式,封装到我们的项目工程的工具包里
方式1:使用JSON序列和反序列化
使用json操作的这个方式是比较简单的,容易想到也易实现。直接上代码:
package main import ( "encoding/json" "fmt" "time" ) type Person struct { Name string `json:"name"` Address string `json:"address"` } func main() { t := time.Now().UnixNano() m := make(map[string]interface{}) person := Person{ Name: "zhangsan", Address: "北京海淀", } j, _ := json.Marshal(person) json.Unmarshal(j, &m) fmt.Println(m) fmt.Println(fmt.Sprintf("JSON-duration:%d", time.Now().UnixNano() - t)) }
输出结果:
map[address:北京海淀 name:zhangsan]
JSON-duration:174000
方式2:使用反射
通过反射机制,灵活的做类型转换。具体实现:
package main import ( "fmt" "reflect" "time" ) type Person struct { Name string `json:"name"` Address string `json:"address"` } func main() { t := time.Now().UnixNano() m := make(map[string]interface{}) person := Person{ Name: "zhangsan", Address: "北京海淀", } elem := reflect.ValueOf(&person).Elem() relType := elem.Type() for i := 0; i < relType.NumField(); i++ { name := relType.Field(i).Name m[name] = elem.Field(i).Interface() } fmt.Println(m) fmt.Println(fmt.Sprintf("反射-duration:%d", time.Now().UnixNano() - t)) }
输出结果:
map[Address:北京海淀 Name:zhangsan]
反射-duration:60000
两种方式对比
执行效率:
使用反射的效率,明显比使用json的效率要高,接近3倍
输出结果:
使用json能达到预期,正常解析出结构体tag;
使用反射未能达到预期,未解析出结构体tag,字段是以结构体定义为准
封装到工具包
基于上面两种方式的对比,我们决定采用反射机制,并对结构体tag解析做兼容,优雅的将struct转换为map,并封装到工具包中
具体实现,工具包代码:
package utils import ( "reflect" "strings" ) type IStruct interface { GetStructData() interface{} } //struct转map //使用反射实现,完美地兼容了json标签的处理 func StructToMap(st IStruct) map[string]interface{} { m := make(map[string]interface{}) in := st.GetStructData() val := reflect.ValueOf(in) if val.Kind() == reflect.Ptr { val = val.Elem() } if val.Kind() != reflect.Struct { return m } relType := val.Type() for i := 0; i < relType.NumField(); i++ { name := relType.Field(i).Name tag := relType.Field(i).Tag.Get("json") if tag != "" { index := strings.Index(tag, ",") if index == -1 { name = tag } else { name = tag[:index] } } m[name] = val.Field(i).Interface() } return m }
测试代码:
package main import ( "fmt" "learn-go/utils" "time" ) type Person struct { Name string `json:"name"` Address string `json:"address"` } //注意:必须实现这个方法,才能正确调用工具包转换方法 func (p Person) GetStructData() interface{} { return p } func main() { t := time.Now().UnixNano() m := make(map[string]interface{}) person := Person{ Name: "zhangsan", Address: "北京海淀", } m = utils.StructToMap(person) fmt.Println(m) fmt.Println(fmt.Sprintf("反射2-duration:%d", time.Now().UnixNano() - t)) }
输出结果:
map[address:北京海淀 name:zhangsan]
反射2-duration:65000
结论:
执行效率高的同时,输出结果也符合预期,能正确的解析出结构体tag
加载全部内容