教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 golang中的反射

golang中的反射

发布时间:2023-02-21   编辑:jiaochengji.com
教程集为您提供golang中的反射等资源,欢迎您收藏本站,我们将为您提供最新的golang中的反射资源

    Golang中的反射是通过refect实现的,我们今天就来看看他的使用和注意事项。

import "reflect"

//reflect包实现了运行时反射,允许程序操作任意类型的对象。
//典型用法是用静态类型interface{}保存一个值,通过调用TypeOf获取其动态类型信息,
//该函数返回一个Type类型值。调用ValueOf函数返回一个Value类型值,
//该值代表运行时的数据。Zero接受一个Type类型参数并返回一个代表该类型零值的Value类型值。

    首先我们来查看官方文档中关于他的介绍,从这里我们可以看到,他的使用场景跟interface是分不开的,然后还可以了解到他的基本方法包含一个返回TypeOf一个ValueOf。然后我们来继续往下看他的TypeOf和ValueOf的使用。

TypeOf && ValueOf:

    从这里可以看到他们接受一个interface参数返回一个type OR Value 类型,我们来测试一把:

   返回值:

    在这里我们可以清楚的看到他的返回值及其类型,他会自动转化为reflect类型的。这里很重要小伙伴们要注意哦,虽然你看到的返回值是float64没错。而且他也返回了type为float64其实他的类型已经被转变。

    接下来我们在看看他的其他方法,其中开局我们提到的interface在这里我们还没有使用。

如何获取接口interface中的信息的呢,话不多说上实例:

1) 已知原有类型

 

    在这里我们先将参数转化为reflect类型,然后通过Interface方法将其转化为interface类型,然后使用类型断言来将变量指回到flioat64类型。这里需要注意的是他不仅可以对值使用而且可以对地址使用,从上例中我们可以看到他并没有创建一个新的对象而是继续指回到原有对象地址。

总结:

  1. 转换的时候,如果类型不完全符合,直接会触发panic,这里需要注意的是完全符合。
  2. 转换的时候,是区分指针和值的
  3. 反射是可以将反射对象转化为接口类型对象的

2)不知原有类型

package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Id   int
	Name string
	Age  int
}

func (u User) ReflectCallFunc() {
	fmt.Println("Allen.Wu ReflectCallFunc")
}

func main() {

	user := User{1, "Allen.Wu", 25}

	DoFiledAndMethod(user)

}

// 通过接口来获取任意参数,然后一一揭晓
func DoFiledAndMethod(input interface{}) {

	getType := reflect.TypeOf(input)
	fmt.Println("get Type is :", getType.Name())

	getValue := reflect.ValueOf(input)
	fmt.Println("get all Fields is:", getValue)

	// 获取方法字段
	// 1. 先获取interface的reflect.Type,然后通过NumField进行遍历
	// 2. 再通过reflect.Type的Field获取其Field
	// 3. 最后通过Field的Interface()得到对应的value
	for i := 0; i < getType.NumField(); i   {
		field := getType.Field(i)
		value := getValue.Field(i).Interface()
		fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value)
	}

	// 获取方法
	// 1. 先获取interface的reflect.Type,然后通过.NumMethod进行遍历
	for i := 0; i < getType.NumMethod(); i   {
		m := getType.Method(i)
		fmt.Printf("%s: %v\n", m.Name, m.Type)
		//使用方法
		getaddrValue := reflect.ValueOf(input)
		getaddrValue.MethodByName(m.Name).Call(nil)
	}
}

输出部分:

  我们可以看到以上示例中,我们先定义了一个User结构体并且赋予了他 ReflectCallFunc方法,然后我们在后边的操作用尝试是用反射来获取并使用他的方法。

  属性获取:我们通过NumField方法来获取这个结构体所包含的属性个数并以此进行遍历,然后通过Field方法取值并打印。

  方法获取:我们通过NumMethod方法来获取这个结构体所包含的方法个数并以此进行遍历,然后通过Method方法可以获取到struct中方法的对象,我们后边进行了方法的调用,直接针对刚才获取的方法对象使用Call方法来调用,因为这里我们的方法是无参数的,所以我们直接给call中传入一个nil即可,如果这是的方法是包含参数的,那么我们需要构造一个[]reflect.Value切片,在切片中append我们需要传入的参数,需要注意的是这里传入的参数依然为reflect类型对象,如下方式使用:

params := make([]reflect.Value, 1)
params[0] = reflect.ValueOf(18)
mtV.MethodByName("SetI").Call(params)

如何修改interface中的变量值

    用指针传递了,因为只有以指针方式传递才能够修改我们的实际变量。 返回展示:

    如上我们使用了指针传递的方式来使用relect方法,这里我们使用elem()方法来重新指会数据的原类型,那么有的童鞋可能要稳了Elem方法是个什么东西呢,我们来带大家看一下

    看到这里可能又有疑问Kind又是个什么东西呢

    看到这里我相信大家应该就懂了,原来我们的kind方法就是返回一个值的分类。

   那么有的同学又要问了,我们不是已经拿到原有值得指针了么为什么还是调用elem方法来进行重新指定呢,不要忘了我们前边说到的,这里reflect会重新定义为refect对象类型而不是我们的原有值类型,所以这里我们还需要拿到他在进一步的值确认操作。

    好,继续回到我们的正题,继续解析我们上边的代码,当我们使用elem方法获取了value原本值后就可以继续我们后边的操作了,接下来调用我们的setfloat方法对我们的值进行修改就可以了,这里为什么用setfloat方法呢,因为我们传进来的就是一个float类型的参数啊,相关的方法还有很多,童靴们可以自行去文档中查看他的一个相关使用。

Golang中的reflect性能,

    因为在使用过程中我们的relect.value是一个具体的值,而不是一个可以复用的反射对象,所以每次反射都要重新对其进行重新分配,还涉及到GC,而且在使用过程中多使用大量循环,所以其性能并不是很好。童靴们在使用过程中应注意不要用力过猛哦。

    好,今天我们对于Golang中反射的介绍就到这里,其他还有很多内容官方文档中都有较好的解释,如果有什么不懂得欢迎小伙伴们提问。

golang中文官方文档:https://studygolang.com/pkgdoc

到此这篇关于“golang中的反射”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Go语言学习之reflect包(The way to go)
golang反射——执行函数
golang的反射机制与实践(上)
C#反射的一些基本应用
golang 映射 map 简介
go-反射机制
Golang 映射 声明使用原理及方法
golang-反射机制
图解 Go 反射实现原理
Golang使用reflect操作struct

[关闭]
~ ~