Go结构体转map 性能&数据结构实现与对比

3 篇文章 0 订阅
1 篇文章 0 订阅
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

![在这里插入图片描述](https://img-blog.csdnimg.cn/c6c658794e0c47538fdec1bccff4536a.png

这里基本数据类型变成了json.Number类型但是数据结构中使用的tag还是完美适配转换了

2.2 手写转换->map

在这里插入图片描述

基本数据类型完美转换成功并且tag也完美适配

2.3 structs->map

在这里插入图片描述

基本数据类型完美适配,但是在打印类型的时候存在差异

三、时间复杂度

  1. structs->map 1us
  2. 手写转换->map 2us
  3. 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}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值