go语言反射改属性的值 golang反射底层实现原理( 二 )


接口变量r的pair中将记录如下信息:(tty, *os.File),这个pair在接口变量的连续赋值过程中是不变的,将接口变量r赋给另一个接口变量w:
接口变量w的pair与r的pair相同 , 都是:(tty, *os.File),即使w是空接口类型 , pair也是不变的 。
interface及其pair的存在,是Golang中实现反射的前提,理解了pair , 就更容易理解反射 。反射就是用来检测存储在接口变量内部(值value;类型concrete type) pair对的一种机制 。
既然反射就是用来检测存储在接口变量内部(值value;类型concrete type) pair对的一种机制 。那么在Golang的reflect反射包中有什么样的方式可以让我们直接获取到变量内部的信息呢? 它提供了两种类型(或者说两个方法)让我们可以很容易的访问接口变量内容,分别是reflect.ValueOf() 和 reflect.TypeOf(),看看官方的解释
reflect.TypeOf()是获取pair中的type,reflect.ValueOf()获取pair中的value,示例如下:
当执行reflect.ValueOf(interface)之后,就得到了一个类型为”relfect.Value”变量,可以通过它本身的Interface()方法获得接口变量的真实内容,然后可以通过类型判断进行转换,转换为原有真实类型 。不过,我们可能是已知原有类型,也有可能是未知原有类型,因此,下面分两种情况进行说明 。
已知类型后转换为其对应的类型的做法如下,直接通过Interface方法然后强制转换,如下:
示例如下:
很多情况下,我们可能并不知道其具体类型 , 那么这个时候 , 该如何做呢?需要我们进行遍历探测其Filed来得知,示例如下:
通过运行结果可以得知获取未知类型的interface的具体变量及其类型的步骤为:
通过运行结果可以得知获取未知类型的interface的所属方法(函数)的步骤为:
reflect.Value是通过reflect.ValueOf(X)获得的 , 只有当X是指针的时候,才可以通过reflec.Value修改实际变量X的值,即:要修改反射类型的对象就一定要保证其值是“addressable”的 。
示例如下:
这算是一个高级用法了,前面我们只说到对类型、变量的几种反射的用法,包括如何获取其值、其类型、如果重新设置新值 。但是在工程应用中 , 另外一个常用并且属于高级的用法 , 就是通过reflect来进行方法【函数】的调用 。比如我们要做框架工程的时候,需要可以随意扩展方法,或者说用户可以自定义方法,那么我们通过什么手段来扩展让用户能够自定义呢?关键点在于用户的自定义方法是未可知的,因此我们可以通过reflect来搞定
示例如下:
Golang的反射很慢 , 这个和它的API设计有关 。在 java 里面,我们一般使用反射都是这样来弄的 。
这个取得的反射对象类型是 java.lang.reflect.Field 。它是可以复用的 。只要传入不同的obj,就可以取得这个obj上对应的 field 。
但是Golang的反射不是这样设计的:
这里取出来的 field 对象是 reflect.StructField 类型,但是它没有办法用来取得对应对象上的值 。如果要取值,得用另外一套对object,而不是type的反射
这里取出来的 fieldValue 类型是 reflect.Value,它是一个具体的值,而不是一个可复用的反射对象了 , 每次反射都需要malloc这个reflect.Value结构体 , 并且还涉及到GC 。
Golang reflect慢主要有两个原因
上述详细说明了Golang的反射reflect的各种功能和用法,都附带有相应的示例,相信能够在工程应用中进行相应实践,总结一下就是:
golang反射自定义tag维基百科中反射的定义:在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力 。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为 。

推荐阅读