Golang reflect反射的使用实例

 更新时间:2023年05月11日 11:36:51   作者:常鱼  
Golang反射的错误大多数都来自于调用了一个不适合当前类型的方法,而且,这些错误通常是在运行时才会暴露出来,而不是在编译时,如果我们传递的类型在反射代码中没有被覆盖到那么很容易就会panic,本文就介绍一下使用go反射时很大概率会出现的错误,需要的可以参考一下

首先有一段以下结构体的定义

type User struct {
	UserName string
	UserId   int `name:"uid"`
}

初始化一个结构体的实例

u := User{"octoboy", 101}

获取字段名

首先获取变量的Type变量

t := reflect.TypeOf(u)

需要注意的是,如果传入的u是个指针,比如&User{"octoboy", 101}

if t.Kind() == reflect.Ptr {
	t = t.Elem()
}

这里通过Kind()函数获取变量的类型,判断如果类型为指针 需要使用Elem()获取指针指向的内容。

然后遍历结构体的字段,获取其字段名称

	for i := 0; i < t.NumField(); i++ {
		fmt.Println(t.Field(i).Name)
	}

输出结果:

UserName

UserId

获取字段类型和值

v := reflect.ValueOf(u)
if v.Kind() == reflect.Ptr { //类型为指针 需要取elem
	v = v.Elem()
}

获取字段的值或者赋值,需要用到ValueOf方法

for i := 0; i < v.NumField(); i++ {
	//v.Field(i).Int() v.Field(i).String() 都可以把值返回出来,相当于断言 类型不匹配会直接panic
	//直接断成interface 任意类型
	fmt.Println(v.Field(i).Interface())
}

输出结果:

zyg

101

继续输出成员变量的类型

for i := 0; i < v.NumField(); i++ {
	fmt.Println(v.Field(i).Kind())
}

输出结果:

string

int

设置字段值

静态赋值

	//设置字段值
	va := reflect.ValueOf(&u) //这里必须使用指针 否则后面调用Set无法使用无地址的值
	if va.Kind() == reflect.Ptr { //类型为指针 需要取elem 意为取它指向的内容值
		va = va.Elem()
	for i := 0; i < va.NumField(); i++ {
		//两种方法取设置字段的值,第二种更为统一
		if va.Field(i).Kind() == reflect.String {
			//重要 如果需要使用set取修改u中的值,需要在ValueOf中传入u的地址。否则会因为SetString使用了一个不能被寻址的值而造成panic
			va.Field(i).SetString("octoboy")
		}
		if va.Field(i).Kind() == reflect.Int {
			va.Field(i).Set(reflect.ValueOf(123))
		}
	}

interface切片映射成结构体(动态赋值)

	//练手
	values := []interface{}{"octoboy", 123}
	for i := 0; i < va.NumField(); i++ {
		if reflect.ValueOf(values[i]).Kind() == va.Field(i).Kind() {
			va.Field(i).Set(reflect.ValueOf(values[i]))
		}
	}

打印以上两种结构题变量

输出结果:

&{octoboy 123}

进阶—map映射成结构体

有如下代码

	//练习 把map映射成struct
	set := map[string]interface{}{
		"UserName": "zyg",
		"UserId":   101,
		"Age":      19,
		"Sex":      1,
	}
	user := &User{}
	MapToStruct(set, user)
	fmt.Println(user)

要求将map映射到user结构题中,即如果User的字段名如存在于map的key中,则将对应的value值赋给user结构题的成员变量

有如下实现

//str类型为interface{} 代表可以传入任意的结构体
func MapToStruct(m map[string]interface{}, str interface{}) {
	val := reflect.ValueOf(str)
	if val.Kind() != reflect.Ptr {//必须是指针 否则无法用Set赋值
		panic(any("must be ptr!"))
	}
	val = val.Elem()
	if val.Kind() != reflect.Struct { //指针指向的必须是结构体
		panic(any("must be struct"))
	}
	for i := 0; i < val.NumField(); i++ {
		name := val.Type().Field(i).Name //value转type后取字段名称
		if v, ok := m[name]; ok {        //如果根据tag做映射,就使用val.Type().Field(i).Tag.Get("name")作为key
			if reflect.ValueOf(v).Kind() == val.Field(i).Kind() {
				val.Field(i).Set(reflect.ValueOf(v))
			}
		}
	}
}

总结

1.TypeOf 用Name 获取字段名,也可以用Kind获取字段的类型;ValueOf 只能用Kind获取字段的类型。

2.使用reflect.ValueOf(u).Type()转成type,可以与reflect.TypeOf(u)达到一样的效果

3.如果要使用Set,SetString等方法为其赋值,reflect.ValueOf(u)这里的u必须传入一个指针,否则无法寻址,会出现panic

4.reflect.ValueOf(u).Interface()可以获取值,在实际使用过程中往往会将返回结果断言成一个接口类型去调用接口函数

到此这篇关于golang reflect反射的使用实例的文章就介绍到这了,更多相关go reflect反射内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang分布式注册中心实现流程讲解

    Golang分布式注册中心实现流程讲解

    这篇文章主要介绍了Golang分布式注册中心实现流程,注册中心可以用于服务发现,服务注册,配置管理等方面,在分布式系统中,服务的发现和注册是非常重要的组成部分,需要的朋友可以参考下
    2023-05-05
  • Golang中json和jsoniter的区别使用示例

    Golang中json和jsoniter的区别使用示例

    这篇文章主要介绍了Golang中json和jsoniter的区别使用示例,本文给大家分享两种区别,结合示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2023-12-12
  • logrus日志自定义格式操作

    logrus日志自定义格式操作

    这篇文章主要介绍了logrus日志自定义格式操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • Golang通脉之数据类型详情

    Golang通脉之数据类型详情

    这篇文章主要介绍了Golang通脉之数据类型,在编程语言中标识符就是定义的具有某种意义的词,比如变量名、常量名、函数名等等,Go语言中标识符允许由字母数字和_(下划线)组成,并且只能以字母和_开头,更详细内容请看下面文章吧
    2021-10-10
  • golang 的string与[]byte转换方式

    golang 的string与[]byte转换方式

    这篇文章主要介绍了golang 的string与[]byte转换方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • Go语言实现AzDG可逆加密算法实例

    Go语言实现AzDG可逆加密算法实例

    这篇文章主要介绍了Go语言实现AzDG可逆加密算法,实例分析了AzDG可逆加密算法的实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02
  • 用Go+Redis实现分布式锁的示例代码

    用Go+Redis实现分布式锁的示例代码

    在分布式的业务中 , 如果有的共享资源需要安全的被访问和处理 , 那就需要分布式锁,本文主要介绍了用Go+Redis实现分布式锁的示例代码,感兴趣的可以了解一下
    2021-12-12
  • go module化 import 调用本地模块 tidy的方法

    go module化 import 调用本地模块 tidy的方法

    这篇文章主要介绍了go module化 import 调用本地模块 tidy的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-09-09
  • Golang分布式锁详细介绍

    Golang分布式锁详细介绍

    分布式锁是控制分布式系统之间同步访问共享资源的一种方式。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源时,需要通过一些互斥手段来防止彼此之间的干扰以保证一致性,在这种情况下,就需要使用分布式锁了
    2022-10-10
  • 一文详解Golang使用接口支持Apply方法的配置模式

    一文详解Golang使用接口支持Apply方法的配置模式

    这篇文章主要为大家介绍了一文详解Golang使用接口支持Apply方法的配置模式,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01

最新评论