[Go关于反射] reflect包

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Go关于反射] reflect包相关的知识,希望对你有一定的参考价值。

参考自liwenzhou

ORM库要用到, 记录一下.

文章目录

reflect.TypeOf() 获取对象类型

在Go语言中,使用reflect.TypeOf()函数可以获得任意值的类型对象(reflect.Type

程序通过类型对象可以访问任意值的类型信息。

func reflectType(x interface)
	v := reflect.TypeOf( x )
	fmt.Printf("type: %v\\n",v )

func main()
	var a float32 = 3.14
	reflectType( a ) // type: float32
	var b int64 = 100
	reflectType( b ) // type: int64

type name和type kind

type tk int64

var(
	a *float32 //指针
	b tk //自定义类型
	by byte //类型别名
	user = User "cl",20 
)

type User struct 
	Name string
	Age int


func reflectType(x interface )
	temp := reflect.TypeOf( x )
	fmt.Printf("type: %v kind: %v\\n", temp.Name(),temp.Kind() )


func main()
	reflectType( a )
	reflectType( b )
	reflectType( by )  // byte是官方定义的类型,所以输出和自定义的不一样
	reflectType( user )

输出为

type:  kind: ptr
type: tk kind: int64
type: uint8 kind: uint8
type: User kind: struct

可以发现Kind总是比Type更接近底层, 而Type则是输出自定义类型的名字而不是底层

Go语言的反射中像数组、切片、Map、指针等类型的变量,它们的.Name()都是返回空。

reflect.ValueOf()

reflect.ValueOf()返回reflect.Value类型,其中包含了原始值的值信息。reflect.Value与原始值之间可以互相转换。

func reflectValue(x interface)
	v := reflect.ValueOf(x)
	k := v.Kind()
	switch k 
	case reflect.Int64:
		// v.Int()从反射中获取整型的原始值,然后通过int64()强制类型转换
		fmt.Printf("type is int64, value is %d\\n", int64(v.Int()))
	case reflect.Float32:
		// v.Float()从反射中获取浮点型的原始值,然后通过float32()强制类型转换
		fmt.Printf("type is float32, value is %f\\n", float32(v.Float()))
	case reflect.Float64:
		// v.Float()从反射中获取浮点型的原始值,然后通过float64()强制类型转换
		fmt.Printf("type is float64, value is %f\\n", float64(v.Float()))
	


func main() 
	var a float32 = 3.14
	var b int64 = 100
	reflectValue(a) // type is float32, value is 3.140000
	reflectValue(b) // type is int64, value is 100

reflect.Value.Elem()获取指针对应的值并修改

使用反射修改变量值

func reflectSetValue1(x interface) 
	v := reflect.ValueOf(x)
	if v.Kind() == reflect.Int64 
		v.SetInt(200) //修改的是副本,reflect包会引发panic
	

func reflectSetValue2(x interface) 
	v := reflect.ValueOf(x)
	//fmt.Println( v.Kind() )
	//fmt.Println( v.Elem().Kind() )
	// 反射中使用 Elem()方法获取指针对应的值
	if v.Elem().Kind() == reflect.Int64 
		v.Elem().SetInt(200)
	

func main() 
	var a int64 = 100
	// reflectSetValue1(a) //panic: reflect: reflect.Value.SetInt using unaddressable value
	reflectSetValue2(&a)
	fmt.Println(a)

reflect.Indirect()于reflect.elem()区别

// Indirect returns the value that v points to.
// If v is a nil pointer, Indirect returns a zero Value.
// If v is not a pointer, Indirect returns v.
func Indirect(v Value) Value

Indirect返回 v v v指向的值

v v v是空指针, 返回 0 0 0

v v v不是指针,返回 v v v本身

大概意思就是把指针值转为原始值

比如下面,传入一个指针的interface转化为原始值reflect.Type的做法

type User struct
	name string
	age int
	addr string


func main()
	uu := User"tom", 27, "beijing"
	u := &uu
	v := reflect.ValueOf(u)

	t := reflect.TypeOf(u)
	fmt.Println("TypeOf=", t)

	t1 := reflect.Indirect(v).Type()
	fmt.Println("t1=", t1)

如果reflect.Value是指针,则v.Elem()等效于reflect.Indirect(v)

如果不是指针,则它们不是等效的:

如果该值是接口,reflect.Indirect(v)则将返回相同的值,而v.Elem()将返回所包含的动态值。
如果该值是其他值,则将感到v.Elem()引发的panic

reflect.Indirect助手用于需要接受特定类型或指向该类型的指针的情况。

结构体反射

任意值通过reflect.TypeOf()获得反射对象信息后,如果它的类型是结构体

可以通过反射值对象(reflect.Type)的NumField()Field()方法获得结构体成员的详细信息。

type student struct 
	Name  string `json:"name"`
	Score int    `json:"score"`


func main() 
	stu1 := student
		Name:  "小王子",
		Score: 90,
	

	t := reflect.TypeOf(stu1)
	fmt.Println(t.Name(), t.Kind()) // student struct
	// 通过for循环遍历结构体的所有字段信息
	for i := 0; i < t.NumField(); i++ 
		field := t.Field(i)
		fmt.Printf("name:%s index:%d type:%v json tag:%v\\n", field.Name, field.Index, field.Type, field.Tag.Get("json"))
	

	// 通过字段名获取指定结构体字段信息
	if scoreField, ok := t.FieldByName("Score"); ok 
		fmt.Printf("name:%s index:%d type:%v json tag:%v\\n", scoreField.Name, scoreField.Index, scoreField.Type, scoreField.Tag.Get("json"))
	

遍历结构体包含的所有方法并调用

// 给student添加两个方法 Study和Sleep(注意首字母大写)
func (s student) Study() string 
	msg := "好好学习,天天向上。"
	fmt.Println(msg)
	return msg


func (s student) Sleep() string 
	msg := "好好睡觉,快快长大。"
	fmt.Println(msg)
	return msg


func printMethod(x interface) 
	t := reflect.TypeOf(x)
	v := reflect.ValueOf(x)

	fmt.Println(t.NumMethod())
	for i := 0; i < v.NumMethod(); i++ 
		methodType := v.Method(i).Type()
		fmt.Printf("method name:%s\\n", t.Method(i).Name)
		fmt.Printf("method:%s\\n", methodType)
		// 通过反射调用方法传递的参数必须是 []reflect.Value 类型
		var args = []reflect.Value
		v.Method(i).Call(args)
	

以上是关于[Go关于反射] reflect包的主要内容,如果未能解决你的问题,请参考以下文章

[Go关于反射] reflect包

[Go关于反射] reflect包

Go反射中的type和kind比较

Go反射中的type和kind比较

一文初探 Go reflect 包

Go - reflection