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网络编程Net包的使用

    深入了解Golang网络编程Net包的使用

    net包主要是增加 context 控制,封装了一些不同的连接类型以及DNS 查找等等,同时在有需要的地方引入 goroutine 提高处理效率。本文主要和大家分享下在Go中网络编程的实现,需要的可以参考一下
    2022-07-07
  • Swaggo零基础入门教程

    Swaggo零基础入门教程

    swagger是一套基于OpenAPI规范构建的开源工具,使用RestApi。swagger-ui呈现出来的是一份可交互式的API文档,可以直接在文档页面尝试API的调用
    2023-01-01
  • 详解Golang如何动态获取配置文件

    详解Golang如何动态获取配置文件

    项目中经常获取一些常用配置文件,当有配置文件中的参数被修改后,如何的实时获取配置文件就很关键了,下面小编就来讲讲如何利用viper实时获取配置文件吧
    2023-08-08
  • Golang中slice删除元素的性能对比

    Golang中slice删除元素的性能对比

    go没有对删除切片元素提供专用的语法或者接口,需要使用切片本身的特性来删除元素,下面这篇文章主要给大家介绍了关于Golang中slice删除元素的性能对比,需要的朋友可以参考下
    2022-06-06
  • 重学Go语言之文件操作详解

    重学Go语言之文件操作详解

    有很多场景都需要对文件进行读取或者写入,比如读取配置文件或者写入日志文件,在Go语言中,操作文件应该算是一件比较简单的事情,我们在这一篇文章中,一起来探究一下
    2023-08-08
  • GoFrame通用类型变量gvar与interface基本使用对比

    GoFrame通用类型变量gvar与interface基本使用对比

    这篇文章主要为大家介绍了GoFrame通用类型变量gvar与interface基本使用对比,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • 浅谈goland导入自定义包时出错(一招解决问题)

    浅谈goland导入自定义包时出错(一招解决问题)

    这篇文章主要介绍了浅谈goland导入自定义包时出错(一招解决问题),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Golang中对json的优雅处理方式

    Golang中对json的优雅处理方式

    这篇文章主要给大家介绍了关于Golang中对json的优雅处理方式,解析JSON在golang中很麻烦,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-06-06
  • 重学Go语言之数组的具体使用详解

    重学Go语言之数组的具体使用详解

    Go的数组是一种复合数据类型,在平时开发中并不常用,更常用的是切片(slice),可以把切片看作是能动态扩容的数组,切片的底层数据结构就是数组,所以数组虽不常用,但仍然有必要掌握
    2023-02-02
  • golang设置http response响应头与填坑记录

    golang设置http response响应头与填坑记录

    这篇文章主要给大家介绍了关于golang设置http response响应头与填坑记录的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-08-08

最新评论