golang反射底层实现原理,go的反射机制
00-1010 1.倒影2的介绍和简介。反射3的数据结构。如何通过反射对象来修改原始数据对象的值?
00-1010在计算机科学中,反射是指计算机程序在运行时访问、检测和修改自身状态或行为的能力。打个比喻,反射是指程序在运行时可以“观察”和修改自己的行为。
需要反射的 2 个常见场景:
有时候你需要写一个函数,但是你不知道传递给你的参数类型是什么。可能是没约定吧。也可能是传入的类型很多,这些类型无法统一表示。那么倒影就派上用场了。有时需要根据某些条件决定调用哪个函数,比如用户输入。这时候就需要反映函数及其参数,在运行时动态执行函数。Java中动态代理和AOP的实现都依赖于这个操作。对于我们的Go语言来说,它也提供了一个反射机制。
有了前面对接口{}底层数据结构的了解,Go中的每个实例对象都可以分为两种:类型信息和数值信息。而我们Go中提供的反射机制可以分别得到这两条信息。
接口中存储有结构化数据,获取数据对应的内存地址,然后将数据转换到接口中。通过查看接口中的类型结构,可以知道数据的结构。其实以上就是围棋反射的流行原理。
00-1010类型类型接口{//所有类型都可以调用以下函数。//此类型的对齐变量所占用的字节数Align() int//如果是struct的字段,则Align field Align()int//返回类型方法集Method(int)Method//Get Method by Name(string)(Method,Bool)//获取类型方法集NumMethod()int//type Name()string//返回类型所在的路径,如:encoding/base 64 pgpath()string//返回类型的大小Sizeof函数,Size() uintptr//返回类型String() string的字符串表示形式//返回类型值Kind() Kind//类型是否实现接口uiimplements(u Type)bool//是否可以赋值给uAssignableTo(u Type) bool//是否可以类型转换为uConvertibleTo(u Type) bool//类型是否可以比较?Comparable() bool//以下函数只能由特定类型调用。//比如:Key,Elem两个方法只能是Map type来调用//type Bits()int//占用的位数和返回通道的方向。只能是chan类型调用ChanDir() ChanDir//类型是否是变量参数只能是func类型调用//比如t是func类型(x int,Y.float64)//然后t . is variadic()==truesvariadic()bool//返回内部子元素类型。只有类型Array、Chan、Map、Ptr或Slice可以调用Elem() Type//返回结构类型的第I个字段,只能由结构类型调用。//如果I超过字段总数,则返回PanicField(i int) StructField//嵌套结构的字段fieldbyindex(index[]int)struct field//字段field byname(name string)(struct field,Bool)//FieldByNameFunc返回带有名称的结构字段//返回字段fieldbyname func(match func(string)Bool)(struct field,Bool)//获取函数类型//的第I个参数的(i int) Type//中的类型并返回map的键类型。只有类型映射可以调用Key() Type//返回数组的长度,只有类型数组可以调用Len() int//返回类型字段的个数。NumField() int//只能被type Struct调用返回函数类型的输入参数个数NumIn() int//返回函数类型的返回值个数NumOut() int//返回函数类型的第I个值的Type out(I int)Type//返回类型结构的相同部分common() *rtype//返回类型结构的不同部分Uncommon () * Uncommon Type}。
alue struct { typ *rtype ptr unsafe.Pointer flag}反射的实现和interface的组成很相似,都是由类型和数据值构成,但是值得注意的是:interface的类型和数据值是在一起的,而反射的类型和数据值是分开的。
Type
和Value
提供了非常多的方法:例如获取对象的属性列表、获取和修改某个属性的值、对象所属结构体的名字、对象的底层类型(underlying type)等等
Go中的反射,在使用中最核心的就两个函数:
reflect.TypeOf(x)reflect.ValueOf(x)这两个函数可以分别将给定的数据对象转化为以上的Type
和Value
。这两个都叫做反射对象
3. 如何通过反射对象来修改原数据对象的值?
在Go中,任何函数的参数都是值的拷贝,而非原数据。
反射函数reflect.ValueOf()
也不例外。我们目前得到的反射对象,都是原对象的copy的反射对象,而非原对象本身,所以不可以修改到原对象.
那如何修改呢?
首先,在Go中要想让函数有副作用,传值必须传指针类型的。
var x float64 = 5.7v := reflect.ValueOf(&x)
时还不行,因为这样反射对象对应的是原数据对象的指针类型,必须要拿到当前类型的值类型(*v)。 Go提供了另外一个方法Elem()
p := v.Elem()fmt.Println(p.CanSet()) // truep.SetFloat(6.6)fmt.Println(x) // 6.6
经过以上操作,就可以修改原数据了,完整过程如下:
var x float64 = 5.7v := reflect.ValueOf(&x)p := v.Elem()fmt.Println(p.CanSet()) // truep.SetFloat(6.6)fmt.Println(x) // 6.6
到此这篇关于Go反射底层原理及数据结构解析的文章就介绍到这了,更多相关 Go反射原理内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。