package main
import (
"bytes"
json2 "encoding/json"
"fmt"
"github.com/fatih/structs"
"reflect"
"time"
)
type Pair struct {
Name string `json:"pairName"`
Price float32
Page int
Kk *Mk
Lq Fq
}
type Mk struct {
Ka string
Mk1 int
}
type Fq struct {
name string `json:"fqName"`
Fq1 int `json:"fq1"`
Fq2 int `json:"fq2"`
Fq3 int `json:"fq3"`
Fq4 int `json:"fq4"`
Fq5 int `json:"fq5"`
Fq6 int `json:"fq6"`
Fq7 int `json:"fq7"`
Fq8 int `json:"fq8"`
Fq9 int `json:"fq9"`
}
func StructToMap(stc interface{}) map[string]interface{} {
newMap := make(map[string]interface{})
t := reflect.TypeOf(stc)
v := reflect.ValueOf(stc)
fields := t.NumField()
for i := 0; i < fields; i++ {
key := t.Field(i).Name
// 解析注解key
if t.Field(i).Tag.Get("json") != "" {
key = t.Field(i).Tag.Get("json")
}
// 解析结构体类型
if v.Field(i).Kind() == reflect.Struct {
newMap[key] = StructToMap(v.Field(i).Interface())
continue
}
// 解析指针类型
if v.Field(i).Kind() == reflect.Ptr {
newMap[key] = StructToMap(v.Field(i).Elem().Interface())
continue
}
// 解析基本类型
newMap[key] = convert(v.Field(i))
}
return newMap
}
func convert(field reflect.Value) interface{} {
// todo 其它类型自行支持
switch field.Type().Name() {
case reflect.String.String():
return field.String()
case reflect.Int.String(), reflect.Int64.String():
return field.Int()
case reflect.Int8.String():
return int8(field.Int())
case reflect.Float32.String():
return float32(field.Float())
case reflect.Float64.String():
return field.Float()
case reflect.Complex64.String():
return complex64(field.Complex())
case reflect.Complex128.String():
return field.Complex()
return float32(field.Float())
default:
panic(fmt.Sprintf("未知的类型%s", field.Type().Kind()))
}
return nil
}
func JsonToMap(variable interface{}) {
n := make(map[string]interface{})
json, err := json2.Marshal(variable)
if err != nil {
panic(err.Error())
}
d := json2.NewDecoder(bytes.NewBuffer(json))
d.UseNumber()
if errs := d.Decode(&n); errs != nil {
panic(err.Error())
}
fmt.Printf("结构体转Json到Map %v\n", n)
DisplayMap(n)
}
func DisplayMap(maps map[string]interface{}) {
fmt.Println("-----------------------------------------------")
for k, v := range maps {
fmt.Printf("k-type: %T, v-type: %T ", k, v)
fmt.Println("k:", k, "v:", v)
}
fmt.Println("-----------------------------------------------")
}
func main() {
book := Pair{Name: "aa", Price: 12.3, Page: 20, Kk: &Mk{"aaa", 1}, Lq: Fq{"fq", 22222, 333, 3, 4, 5, 6, 7, 8, 9}}
start := time.Now() // 获取当前时间
// 缺点 指针结构体无法转换,无法确定转换后的值类型
JsonToMap(book)
elapsed := time.Since(start)
fmt.Println("该函数执行完成耗时:", elapsed, "\n######################################\n")
// 支持结构体 && 结构体指针,转换后能完全兼容原结构属性类型
start = time.Now() // 获取当前时间
m := StructToMap(book)
fmt.Printf("结构体到Map %v\n", m)
DisplayMap(m)
elapsed = time.Since(start)
fmt.Println("该函数执行完成耗时:", elapsed, "\n######################################\n")
// 支持结构体 && 结构体指针,解析tag上存在问题
start = time.Now() // 获取当前时间
fmt.Printf("结构体到Map [structs] %v\n", structs.Map(book))
DisplayMap(m)
elapsed = time.Since(start)
fmt.Println("该函数执行完成耗时:", elapsed, "\n######################################\n")
}
一、结构体三种转换方式(json->map、手写转换->map、第三方库structs->map)
1.1 性能对比
1.1.1 json->map
1.1.2 手写转换->map
1.1.3 structs->map
二、数据结构准确性与tag解析
2.1 json->map
这里基本数据类型变成了json.Number类型但是数据结构中使用的tag还是完美适配转换了
2.2 手写转换->map
基本数据类型完美转换成功并且tag也完美适配
2.3 structs->map
基本数据类型完美适配,但是在打印类型的时候存在差异
三、时间复杂度
- structs->map 1us
- 手写转换->map 2us
- json->map 40us
总结来说json->map转换最耗时且数据类型精度不够,手写转换->map 可以完全适配复杂数据类型同时直接解析tag, structs->map 可以完全适配复杂数据类型但是解析tag上存在问题
四、json后的数据对比(structs在嵌套结构体中无法正确解析tag)
json->map {"Kk":{"Ka":"aaa","Mk1":1},"Lq":{"fq1":22222,"fq2":333,"fq3":3,"fq4":4,"fq5":5,"fq6":6,"fq7":7,"fq8":8,"fq9":9},"Page":20,"Price":12.3,"pairName":"aa"}
手写实现->map {"Kk":{"Ka":"aaa","Mk1":1},"Lq":{"fq1":22222,"fq2":333,"fq3":3,"fq4":4,"fq5":5,"fq6":6,"fq7":7,"fq8":8,"fq9":9,"fqName":"fq"},"Page":20,"Price":12.3,"pairNamea"}
structs->map {"Kk":{"Ka":"aaa","Mk1":1},"Lq":{"Fq1":22222,"Fq2":333,"Fq3":3,"Fq4":4,"Fq5":5,"Fq6":6,"Fq7":7,"Fq8":8,"Fq9":9},"Name":"aa","Page":20,"Price":12.3}