脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|shell|

服务器之家 - 脚本之家 - Golang - 一篇学会Go中reflect反射的详细用法

一篇学会Go中reflect反射的详细用法

2024-05-10 16:06战神联盟go Golang

在Go语言的反射机制中,任何接口值都由是一个具体类型和具体类型的值两部分组成的(我们在上一篇接口的博客中有介绍相关概念)。

应用场景

1.判断函数变量是否否和标准

2.验证接口值是否合理如(是否为空,传入的字段是否合规)

3.获取变量的类型进行断言等操作

在Go语言的反射机制中,任何接口值都由是一个具体类型和具体类型的值两部分组成的(我们在上一篇接口的博客中有介绍相关概念)。 在Go语言中反射的相关功能由内置的reflect包提供,任意接口值在反射中都可以理解为由reflect.Type和reflect.Value两部分组成,并且reflect包提供了reflect.TypeOf和reflect.ValueOf两个函数来获取任意对象的Value和Type。

1.结构体中使用反射

  • 获取 2 种类型信息的方法:

reflect.TypeOf() 获取类型信息,返回 Type 类型;

reflect.ValueOf() 获取数据信息,返回 Value 类型。

反射中值的可设置性,可以用 CanSet 方法来判断值是否可以设置。在 Go 中,函数参数的传递都是值拷贝,在反射中要修改值,必须传递指针,并且用 Elem() 方法获取指针的值,然后进行修改。

reflect.ValueOf() 返回的 Value 类型:

  • 它有一个 Type() 方法,返回的是 reflect.Value 的 Type
  • 它有获取 Value 类型值的方法如果我们知道是 float 类型,所以直接用 Float() 方法。如果不知道具体类型呢?由上面例子可知用 Interface() 方法,然后在进行类型断言 v.Interface().(float64) 来判断获取值

v.Kind() 和 v.Type() 区别:

在 type MyInt int 里,v.Kind() 与 v.Type() 返回了不同的类型值,Kind()返回的是 int,Type() 返回的是 MyInt。在 Go 中,可以用 type 关键字定义自定义类型,Kind() 方法返回底层类型。比如还有结构体,指针等类型用 type 定义的,那么 Kind() 方法就可以获取这些类型的底层类型。

案列使用方法

package main

import (
	"fmt"
	"reflect"
)

type Userinfo struct {
	Age      int `id:"iloveyou" num:"222"` //tag标签信息
	UserName string
}

func GetReflickInfo(i interface{}) {
	vl := reflect.ValueOf(i)
	//nii := 200
	fmt.Println("kind ======", vl.Kind())
	if vl.Kind() == reflect.Ptr { //如是指针类型,先取值
		vl = vl.Elem() //Elem方法就是取值操作
	}
	vlt := vl.Type() //获取具体类型,如自定义结构体的类型
	fmt.Println("kind ======type===", vl.Kind(), vlt)
	if vl.Kind() != reflect.Struct {
		fmt.Println("类型:", vlt, " 名字:", vlt.Name(), " 数值:", vl)
		//如是整数种类,又可以修改,CanSet属性为true,则进行修改。
		if vl.Kind() == reflect.Int || vl.Kind() == reflect.Int64 && vl.CanSet() {
			vl.SetInt(100)
			//reflect.New(vlt)是创建了一个vlt类型的指针变量。
			ni := reflect.New(vlt)
			//创建后的ni是reflect.Value对象,需要通过ValueOf来赋值
			ni = reflect.ValueOf(222)
			fmt.Println("修改后int数值:", vl, "新建数值:", ni)
		}
		//如是浮点数种类,又可以修改,CanSet属性为true,则进行修改。
		//可设置性检查:vl.CanSet() 是一个方法,用于确认vl的值是否可以被修改。在Go中,不是所有的反射值都能被设置,比如函数参数或者某些静态类型就不能。如果vl的值可以被改变,CanSet()将返回true。
		if vl.Kind() == reflect.Float32 || vl.Kind() == reflect.Float64 && vl.CanSet() {
			vl.SetFloat(100.11) //调用vl.SetFloat(100.11)方法将变量vl的值设置为100.11。
			fmt.Println("修改后float数值:", vl)
		}
	} else {
		fmt.Println("结构体类型:", vlt, " 名字:", vlt.Name())
		for i := 0; i < vl.NumField(); i++ {
			//vl是具体的值,这里vl.Field(i)就是枚举出每一个成员的值
			//vlt是获取的类型,vlt.Field(i).Name和.Type是枚举出每一个成员的名字和类型
			//也可以使用FieldByName,从指定的成员名获取具体值,vlret:= vl.FieldByName(vlt.Field(i).Name)
			fmt.Println("成员名:", vlt.Field(i).Name, " 类型:", vlt.Field(i).Type, " 数值:", vl.Field(i))
			//如是字符串种类,又可以修改,CanSet属性为true,则进行修改。
			if vl.Field(i).Kind() == reflect.String && vl.Field(i).CanSet() {
				vl.Field(i).SetString("new str")
				fmt.Println("string成员修改后数值:", vl.Field(i))
			}
			//而tag标签信息都是静态的,无须实例化结构体,通过类型vlt可以获取到。
			//这句vlt.Field(i).Tag.Lookup("id")就是枚举出每一个成员的tag标签,看里面是否有id这个key,并返回它的value值
			if idtag, b := vlt.Field(i).Tag.Lookup("id"); b {
				fmt.Println("tag id=", idtag)
			}
			if numtag, b := vlt.Field(i).Tag.Lookup("num"); b {
				fmt.Println("tag num=", numtag)
			}
		}
	}
}

func main() {
	var price float64 = 3.14
	var age int64 = 5
	bd := Userinfo{100, "andy"}
	ns := struct { //定义一个无名结构体
		id   int
		addr string
	}{2, "aa"}
	GetReflickInfo(price)
	GetReflickInfo(&age) //把变量地址传递,所以可以修改。
	GetReflickInfo(&bd)  //把结构体地址传递,所以可以修改。
	fmt.Println(bd)      //打印出修改后的结构体变量
	GetReflickInfo(ns)
}

原文地址:https://www.toutiao.com/article/7366901025199948315/

延伸 · 阅读

精彩推荐
  • Golang详解Go语言中io/ioutil工具的使用

    详解Go语言中io/ioutil工具的使用

    这篇文章主要为大家详细介绍了Go语言中io/ioutil工具的使用,从而简化文件操作。文中是示例代码讲解详细,感兴趣的小伙伴可以了解一下...

    剑客阿良_ALiang12212022-10-11
  • Golang详解Golang如何优雅的终止一个服务

    详解Golang如何优雅的终止一个服务

    后端服务通常会需要创建子协程来进行相应的作业,但进程接受到终止信号或正常结束时,并没有判断或等待子协程执行结束,下面这篇文章主要给大家介绍了...

    磊磊落落爱分享6142022-09-08
  • Golanggo语言使用第三方包 json化结构体操作示例

    go语言使用第三方包 json化结构体操作示例

    这篇文章主要介绍了go语言使用第三方包 json化结构体操作,结合实例形式分析了Go语言ffjson包git安装及结构体转json字符串相关操作技巧,需要的朋友可以参考...

    学习笔记6664512020-05-25
  • Golanggolang实现微信小程序商城后台系统(moshopserver)

    golang实现微信小程序商城后台系统(moshopserver)

    这篇文章主要介绍了golang实现微信小程序商城后台系统(moshopserver),本文通过截图实例代码的形式给大家介绍的非常详细,具有一定的参考借鉴价值,需要...

    HarlanC4502020-06-05
  • Golang使用go gin来操作cookie的讲解

    使用go gin来操作cookie的讲解

    今天小编就为大家分享一篇关于使用go gin来操作cookie的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来...

    stpeace6792020-05-25
  • GolangGolang中的Interface详解

    Golang中的Interface详解

    本文详细讲解了Golang中的Interface,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    qqwx9192022-07-13
  • GolangGo语言创建、初始化数组的常见方式汇总

    Go语言创建、初始化数组的常见方式汇总

    这篇文章主要介绍了Go语言创建、初始化数组的常见方式,实例汇总了Go语言操作数组的常见技巧,具有一定参考借鉴价值,需要的朋友可以参考下 ...

    脚本之家6172020-04-13
  • Golanggoland 恢复已更改文件的操作

    goland 恢复已更改文件的操作

    这篇文章主要介绍了goland 恢复已更改文件的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    疯狂学者10982021-06-05