iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >如何在go语言中利用反射精简代码
  • 343
分享到

如何在go语言中利用反射精简代码

2023-06-05 04:06:42 343人浏览 独家记忆
摘要

这篇文章主要为大家分析了如何在Go语言中利用反射精简代码的相关知识点,内容详细易懂,操作细节合理,具有一定参考价值。如果感兴趣的话,不妨跟着跟随小编一起来看看,下面跟着小编一起深入学习“如何在go语言中利用反射精简代码”的知识吧。反射是 G

这篇文章主要为大家分析了如何在Go语言中利用反射精简代码的相关知识点,内容详细易懂,操作细节合理,具有一定参考价值。如果感兴趣的话,不妨跟着跟随小编一起来看看,下面跟着小编一起深入学习“如何在go语言中利用反射精简代码”的知识吧。

反射是 Go 语言中非常重要的一个知识点。反射是设计优雅程序的法宝,ORM JSON 序列化,参数校验都离不开它,我们今天以一个业务开发中的实例,来简单讲解下反射在日常开发中的用处。

相信大家在使用 go 编写业务代码的时候都会写过这样的代码,这类代码的本质是,将一个集合中的数据按照名称绑定到结构体的对应属性上去,集合的类型不限于 map slice struct 甚至可以是 interface[^interface],

[^interface]: 这个就比较 trick 了

type TestValue struct {        IntValue int        StringValue string        IntArray   []int        StringArray []string    }    dataMap := map[string]string{        "int_value":"1",        "string_value":"str",        "int_array":"[1,2,3]",        "string_array":"[\"1\",\"2\",\"3\"]",    }    config := TestValue{}    if value, ok := dataMap["int_value"]; ok {        config.IntValue, _ = datautil.TransToInt64(value)    }    if value, ok := dataMap["string_value"]; ok {        config.StringValue = value    }    if value, ok := dataMap["int_array"]; ok {        config.IntArray = stringToIntArray(value)    }    if value, ok := dataMap["string_array"]; ok {        config.StringArray = stringToStrArray(value)    }    return config

这部分代码中最挫的地方就是结构体赋值的时候一个一个进行的复制,若整个结构体非常大,赋值的代码可能会写满满一屏,bug出现的几率也就大大增加,我们的目的就是通过反射来简化赋值的步骤,通过一个方法将集合中的数据绑定到结构体上

如何在go语言中利用反射精简代码

反射简述

要做到这一步,我们首先了解下,在 go 语言中,我们的变量是由什么组成的

  • _type 类型信息

  • *data 指向实际值的指针

  • itab 接口方法

图上第一个 type 是一个反射类型对象,表示了变量类型的一些信息,第二个表示结构体属性对应的的 type,包含了结构体属性的一些信息

reflect.Type : /go/src/reflect/value.go:36

如何在go语言中利用反射精简代码

bind function

看到这张图我们大概就明白应该怎样做了,目标是编写一个绑定方法,必须建立一个绑定关系,把这个结构体加上一个 tag ,通过 tag 和 map 中的数据建立关联

// 创建一个具有深刻含义的 tag    type TestValue struct {        IntValue     int            `qiudianzan:"int_value"`                StringValue string        `qiudianzan:"string_value"`        IntArray       []int        `qiudianzan:"int_array"`        StringArray []string    `qiudianzan:"string_array"`    }

紧接着获取结构体的 tag ,通过反射轻而易举的做到了

func bind(configMap map[string]string, result interface{}) error {    v := reflect.ValueOf(result).Elem()    t := v.Type()    for i := 0; i < t.NumField(); i++ {        tag := t.Field(i).Tag.Get("qiudianzan")        fmt.Println(tag)    }

绑定关系完成以后,就需要向结构体写入 map 中的值,这时候问题来了,map 中的数据结构都是 string ,但是结构体属性类型五花八门,并不能直接将 map 中的数据写入,还需要根据结构体属性类型做一步类型转换

v.Field(i).SetInt(res)    v.Field(i).SetUint(res)    v.Field(i).SetFloat(res)    .    .    .

通过反射可以获取属性的两种表示类型的反射对象

reflect.Type    // 静态类型    reflect.Kind    // 底层数据的类型

我们通过下面的例子来确定使用哪一个

type A struct {    }    func main() {        var a A        kinda := reflect.ValueOf(a).Kind()        typea := reflect.TypeOf(a)        fmt.Println(kinda)        fmt.Println(typea)    }struct    main.A

变量 a 的静态类型为 A,但是 a 的底层数据类型则为 struct,所以我们想根据类型解析,这里说的类型是指的 reflect.Kind

通过底层数据类型来转换 map 中的数据

switch v.Field(i).Kind() {        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:            res, err := strconv.ParseInt(value, 10, 64)            if err != nil {                return err            }            v.Field(i).SetInt(res)        case reflect.String:            v.Field(i).SetString(value)        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:            res, err := strconv.ParseUint(value, 10, 64)            if err != nil {                return err            }            v.Field(i).SetUint(res)

再稍稍整理下添加一点细节,一个简单的绑定函数就大功告成了

func bind(configMap map[string]string, result interface{}) error {    // 被绑定的结构体非指针错误返回    if reflect.ValueOf(result).Kind() != reflect.Ptr {        return errors.New("input not point")    }    // 被绑定的结构体指针为 null 错误返回    if reflect.ValueOf(result).IsNil() {        return errors.New("input is null")    }    v := reflect.ValueOf(result).Elem()    t := v.Type()    for i := 0; i < t.NumField(); i++ {        tag := t.Field(i).Tag.Get("json")        // map 中没该变量有则跳过        value, ok := configMap[tag]        if !ok {            continue        }        // 跳过结构体中不可 set 的私有变量        if !v.Field(i).CanSet() {            continue        }        switch v.Field(i).Kind() {        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:            res, err := strconv.ParseInt(value, 10, 64)            if err != nil {                return err            }            v.Field(i).SetInt(res)        case reflect.String:            v.Field(i).SetString(value)        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:            res, err := strconv.ParseUint(value, 10, 64)            if err != nil {                return err            }            v.Field(i).SetUint(res)        case reflect.Float32:            res, err := strconv.ParseFloat(value, 32)            if err != nil {                return err            }            v.Field(i).SetFloat(res)        case reflect.Float64:            res, err := strconv.ParseFloat(value, 64)            if err != nil {                return err            }            v.Field(i).SetFloat(res)        case reflect.Slice:            var strArray []string            var valArray []reflect.Value            var valArr reflect.Value            elemKind := t.Field(i).Type.Elem().Kind()            elemType := t.Field(i).Type.Elem()            value = strings.Trim(strings.Trim(value, "["), "]")            strArray = strings.Split(value, ",")            switch elemKind {            case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:                for _, e := range strArray {                    ee, err := strconv.ParseInt(e, 10, 64)                    if err != nil {                        return err                    }                    valArray = append(valArray, reflect.ValueOf(ee).Convert(elemType))                }            case reflect.String:                for _, e := range strArray {                    valArray = append(valArray, reflect.ValueOf(strings.Trim(e, "\"")).Convert(elemType))                }            }            valArr = reflect.Append(v.Field(i), valArray...)            v.Field(i).Set(valArr)        }    }    return nil}

之前的看起来非常难看的代码瞬间就变得很简单

type TestValue struct {        IntValue int        StringValue string        IntArray   []int        StringArray []string    }    dataMap := map[string]string{        "int_value":"1",        "string_value":"str",        "int_array":"[1,2,3]",        "string_array":"[\"1\",\"2\",\"3\"]",    }    config := TestValue{}    err := bind(dataMap,&config)

在这里只是提供一种绑定的思路,其实在实际开发中,遇到结构体值绑定/校验/格式化/方法绑定,都可以使用类似的思路,避免 one by one 的编写代码。

关于“如何在go语言中利用反射精简代码”就介绍到这了,更多相关内容可以搜索编程网以前的文章,希望能够帮助大家答疑解惑,请多多支持编程网网站!

--结束END--

本文标题: 如何在go语言中利用反射精简代码

本文链接: https://www.lsjlt.com/news/241056.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何在go语言中利用反射精简代码
    这篇文章主要为大家分析了如何在go语言中利用反射精简代码的相关知识点,内容详细易懂,操作细节合理,具有一定参考价值。如果感兴趣的话,不妨跟着跟随小编一起来看看,下面跟着小编一起深入学习“如何在go语言中利用反射精简代码”的知识吧。反射是 G...
    99+
    2023-06-05
  • 如何在Go语言中利用反射功能
    标题:Go语言中的反射功能及代码示例 在Go语言中,反射(Reflection)是一种强大的机制,可以在运行时检查变量的类型和值,通过反射,我们可以动态地调用任意方法、修改变量的值,甚...
    99+
    2024-04-02
  • 利用反射机制优化Go语言代码
    利用反射机制优化 go 语言代码可以:获取类型信息(名称、类型、字段、方法):reflect.typeof()修改值(结构体、切片):reflect.valueof().elem().f...
    99+
    2024-04-08
    go 优化 go语言
  • Go语言中的反射怎么用
    这篇文章主要介绍Go语言中的反射怎么用,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!概述在程序运行期对程序动态的进行访问和修改reflect godoc: https://golang.org/pkg/reflect...
    99+
    2023-06-25
  • 详解如何让Go语言中的反射加快
    目录切入点案例反射基本版优化一:加入缓存策略优化二:利用字段偏移量优化三:更改缓存 key 类型优化四:引入描述符总结最近读到一篇关于 Go 反射的文章,作者通过反射给结构体填充字段...
    99+
    2024-04-02
  • 提升代码可读性:Go语言精简else用法详解
    提升代码可读性:Go语言精简else用法详解 在编写代码时,代码的可读性是至关重要的,它可以帮助我们更好地理解和维护代码,提高代码的质量。在Go语言中,精简else用法可以帮助我们简化...
    99+
    2024-03-13
    go语言 可读性 提升代码 代码可读性
  • 如何在Java中利用反射创建对象
    本篇文章给大家分享的是有关如何在Java中利用反射创建对象,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、什么是反射Java Reflaction in Action中的解释...
    99+
    2023-06-15
  • 将在 Go 语言切片中应用反射和动态类型
    一分耕耘,一分收获!既然打开了这篇文章《将在 Go 语言切片中应用反射和动态类型》,就坚持看下去吧!文中内容包含等等知识点...希望你能在阅读本文后,能真真实实学到知识或者帮你解决心中的疑惑,也欢迎...
    99+
    2024-04-04
  • 如何利用现代化C#语法简化代码
    Intro 最近几个版本的 C# 在语法中有很多的变化,有很多语法能够帮助我们大大简化代码复杂度,使得代码更加简洁,分享几个我觉得比较实用的可以让代码更加简洁的语法 Default...
    99+
    2024-04-02
  • 精简代码结构:Go语言去除else优化技巧分享
    Go语言在编写代码时,很多情况下都会用到if-else语句来进行条件判断。然而,在某些情况下,我们可以优化代码结构,去除else关键字,使得代码更为简洁和易读。下面分享一些去除else...
    99+
    2024-03-12
    优化代码 精简结构 去除else go语言
  • Go语言中的Facade模式:简化代码结构的利器解析
    Golang中的Facade设计模式解析:简化代码结构的利器引言:在软件开发中,代码的组织和管理是十分重要的。当一个项目规模逐渐增大时,代码结构将会变得复杂,难以理解和维护。为了解决这个问题,设计模式应运而生。其中的一个重要设计模式就是Fa...
    99+
    2023-12-20
    利器 Golang 中的 Facade 设计模式 简化代码结构
  • go语言如何编译代码
    go语言编译代码的步骤如下:1、编写Go代码并保存到一个或多个以.go为扩展名的文件中;2、使用命令行界面进入到你的源代码文件所在的目录,并执行”go build“命令来编译代码;3、编译成功后,切换到可执行文件所在的目录,并执行”./ma...
    99+
    2023-12-12
    go语言 Golang go语言编译
  • Go语言中如何实现路由的反向代理
    Go语言中实现路由的反向代理引言:随着互联网的发展,网络请求转发和代理成为了开发中的常见需求。在Go语言中,反向代理是一种常用的技术,它可以将客户端的请求转发到不同的后端服务器。本文将介绍如何使用Go语言实现路由的反向代理。一、什么是反向代...
    99+
    2023-12-17
    Go语言 路由 反向代理
  • 在Go语言中如何实现转码
    近年来,随着互联网的蓬勃发展,各种编程语言也呈现出繁荣的态势。其中,Go语言因为其高性能、易于上手等特点,备受广大程序员的青睐。而在Go语言的应用中,转码这个功能也是十分常见的。今天,就让我们一同深入探讨一下,在Go语言中如何实现转码。一、...
    99+
    2023-05-14
  • Go语言中的映射类型如何使用?
    Go语言中的映射类型如何使用? 在Go语言中,映射(map)是一种内置的数据结构,用于存储键值对。映射允许通过键来快速检索值,类似于其他语言中的字典或哈希表。在本文中,我们将介绍Go语...
    99+
    2024-04-02
  • GO语言中的数组操作算法,如何让代码更简洁?
    在GO语言中,数组是一种非常常见的数据结构,它可以存储一组相同类型的元素。而在进行数组操作时,我们通常需要用到一些算法来实现一些特定的功能,例如查找、排序、去重等。本文将介绍几种常见的数组操作算法,并探讨如何让代码更加简洁。 一、查找算法...
    99+
    2023-10-03
    对象 数组 编程算法
  • 学习 Go 语言:如何在 Linux 上编写代码?
    Go 语言自发布以来,已经成为了一种广泛使用的编程语言。它被设计成一门高效、可靠、简单易用的语言,可应用于各种用途。在本文中,我们将探讨如何在 Linux 操作系统上使用 Go 语言编写代码。 安装 Go 在开始编写 Go 代码之前,...
    99+
    2023-07-28
    关键字 教程 linux
  • 如何在UNIX系统中利用GO语言进行自然语言处理?
    在当今信息化时代,自然语言处理(NLP)越来越受到人们的关注。作为一种高效的编程语言,GO语言在NLP领域也有着广泛的应用。本文将为大家介绍如何在UNIX系统中利用GO语言进行自然语言处理。 一、GO语言介绍 GO语言是由Google公司开...
    99+
    2023-08-14
    unix 索引 自然语言处理
  • 反射之光:探秘 Go 语言中方法的动态调用
    反射在 go 语言中是一种强大的工具,允许程序动态调用方法。具体步骤包括:获取方法元数据 (reflect.method)检索方法类型 (reflect.value)使用方法类型动态调用...
    99+
    2024-04-08
    go语言 反射
  • 如何在Go语言中使用关键字来提高代码质量?
    在编写Go语言代码时,使用关键字是提高代码质量的关键之一。关键字是Go语言中的一些保留单词,它们具有特殊的含义和用途。通过合理使用关键字,可以使代码更加清晰、易读、易维护。本文将介绍如何在Go语言中使用关键字来提高代码质量,并通过演示代码加...
    99+
    2023-09-12
    windows 数据类型 关键字
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作