golang reflect反射的简单入门

目录

获取字段名

获取字段类型和值

设置字段值

静态赋值

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

进阶——map映射成结构体

总结


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

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()可以获取值,在实际使用过程中往往会将返回结果断言成一个接口类型去调用接口函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Go语言中的reflect包提供了一种对程序的静态类型进行操作的方法,即可以在程序运行时动态地调用、检查和更改变量、类型和方法。 首先,reflect包提供了两个重要的类型:Type和Value。Type表示变量的类型,Value则表示变量的值。可以通过reflect.TypeOf和reflect.ValueOf来获取一个变量的Type和Value。 使用reflect包,我们可以在运行时获取变量的类型和值的一些基本信息,例如判断一个变量是否是某个特定类型,或者获取一个变量的名称和值。这在某些情况下可能是非常有用的,比如在编写通用的函数时,需要对不同类型的变量做相同的处理。 此外,reflect包还提供了一些函数来获取、设置和调用变量、类型和方法的具体信息。可以使用reflect.Value的相关方法来获取和设置变量的值,也可以使用reflect.Type的相关方法来获取类型的信息。使用reflect包还可以动态地调用某个值的方法。 需要注意的是,使用reflect包可能会导致一些性能上的损失,因为在运行时需要通过反射来获取变量的信息。因此,在性能要求较高的场景下,尽量避免使用反射。 总结而言,reflect包为我们提供了一种在运行时对变量、类型和方法进行操作的方法,可以通过反射来获取、设置和调用它们的信息。但是,需要注意在性能要求较高的情况下,尽量避免使用反射

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

常鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值