Golang实现优雅的将struct转换为map

 更新时间:2023年01月29日 10:57:53   作者:劲仔Go  
在项目实践中,有时候我们需要将struct结构体转为map映射表,然后基于map做数据裁剪或操作。那么下面我来介绍下常用的两种转换方式,希望对大家有所帮助

前言

在项目实践中,有时候我们需要将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

到此这篇关于Golang实现优雅的将struct转换为map的文章就介绍到这了,更多相关Golang struct转map内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • golang实现java uuid的序列化方法

    golang实现java uuid的序列化方法

    这篇文章主要介绍了golang实现java uuid的序列化方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • golang多维度排序及题解最长连续序列

    golang多维度排序及题解最长连续序列

    这篇文章主要为大家介绍了golang多维度排序及题解最长连续序列示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • golang channel读取数据的几种情况

    golang channel读取数据的几种情况

    本文主要介绍了golang channel读取数据的几种情况,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • GoLang中的sync包Once使用执行示例

    GoLang中的sync包Once使用执行示例

    这篇文章主要介绍了GoLang中的sync包Once使用执行示例,没有学习Once前,大家可能想到 声明一个标识,表示是否初始化过,然后初始化这个标识加锁,更新这个标识,Once包主要用于在并发执行代码的时候,某部分代码只会被执行一次
    2023-03-03
  • Golang 按行读取文件的三种方法小结

    Golang 按行读取文件的三种方法小结

    本文主要介绍了Golang 按行读取文件的三种方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • Go语言中常量定义方法实例分析

    Go语言中常量定义方法实例分析

    这篇文章主要介绍了Go语言中常量定义方法,以实例形式分析了Go语言中常量的定义及使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02
  • Go通过不变性优化程序详解

    Go通过不变性优化程序详解

    这篇文章主要为大家介绍了Go通过不变性优化程序实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • golang之判断元素是否在数组内问题

    golang之判断元素是否在数组内问题

    这篇文章主要介绍了golang之判断元素是否在数组内问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2020-12-12
  • Go代码检查工具golangci-lint安装使用方法

    Go代码检查工具golangci-lint安装使用方法

    这篇文章主要给大家介绍了关于Go代码检查工具golangci-lint安装使用的相关资料,golangci-lint用于许多开源项目中,比如kubernetes、Prometheus、TiDB等都使用golangci-lint用于代码检查,需要的朋友可以参考下
    2024-01-01
  • 如何利用golang运用mysql数据库

    如何利用golang运用mysql数据库

    这篇文章主要介绍了如何利用golang运用mysql数据库,文章对依赖包、db对象注入ApiRouter等内容,需要的小伙伴可以参考一下
    2022-03-03

最新评论