笔者本来是C++开发人员,以前对于反射没太大概念,学了GO以后,才开始接触,在研究了一段时间以后,有了些认识,便整理一个帖子,但愿对你们有所帮助。golang
在学习反射的时候,笔者一直在问本身,反射是什么?为何要用到反射?它是怎么实现的?笔者以为,在知道这些问题的答案以后,才算是真正了解反射。下面笔者便从这些问题来着手整理反射。web
1、反射是什么?
维基百科上的定义:编程
在计算机科学中,反射是指计算机程序在运行时(Run time)能够访问、检测和修改它自己状态或行为的一种能力。用比喻来讲,反射就是程序在运行的时候可以“观察”而且“修改”本身的行为。json
《Go 语言圣经》中是这样定义反射的:数组
Go 语言提供了一种机制在运行时更新变量和检查它们的值、调用它们的方法,可是在编译时并不知道这些变量的具体类型,这称为反射机制。微信
经过上面的描述,咱们能看出来,反射是“元编程”的一种实现手段,它表如今运行阶段,是对运行代码的一种再编译。数据结构
2、反射能干什么?
这里只是针对GO语言的反射来描述,反射主要用在下面两种状况下:函数
场景一:性能
参数的入参是空的interface,也就是说参数的入参须要在该函数被执行的时候,才能知道这个入参究竟是什么类型。学习
这种状况产生的缘由: 每每是函数定义的时候,但愿该入参能够支持不少的数据类型,或者说定义该函数的时候,并无想好这个入参应该是什么数据类型。
例如: json的序列化操做。
场景二:
程序在执行到一处代码的时候,它到底要调用哪个函数,取决于当前传递的数据是什么规则,而不一样的规则须要调用不一样的函数,这种状况下也须要用到反射。
例如:webserver在接收到不一样的uri的时候,须要使用不一样的函数来处理,这就是很典型的一个例子。
全部的事情都有正反两面,反射也不例外,引入反射以后,会有下面的一些很差的地方:
1.代码可读性变低,对开发人员不是那么友好,阅读代码的难度上升一个层级。
2.反射使用后,会避过了编译阶段的类型检查,致使本来有可能在编译阶段发现的问题被隐藏掉。
3.反射对性能影响仍是比较大的,比正常代码运行速度慢一到两个数量级,若是系统对性能要求很高,就须要慎用反射。
3、反射是怎么使用的?
在此以前,咱们须要先看下,反射的三个定律,以下所示:
1.Reflection goes from interface value to reflection object.(反射可以将 interface 中的类型和值转换成真实的反射对象。)
2.Reflection goes from reflection object to interface value.(反射可以将真实的反射对象转变成真实类型。)
3.To modify a reflection object, the value must be settable.(若是像修改反射生成的反射对象,这个数值必须是可修改的。)
定律一:将空接口转换成反射对象
咱们经过reflect.Typeof()来显示,真实的对象类型,例子以下:
func TypeOf(i interface{}) Type // Typeof()的定义能够看出参数是一个空的interface
咱们经过reflect.ValueOf()来显示真实对象存储的数值,例子以下所示:
type Value struct {// contains filtered or unexported fields}
func ValueOf(i interface{})Value // ValueOf的入参也是一个空接口
经过MethodByName来获取对应名称的函数,并调用
备注:GetName()本来只是一个返回值,可是输出结果倒是[Hello]数组的缘由是,Value.Call()函数的返回值是一个[]reflect.Value的数组。
定律二:将反射对象转换成原类型
reflect.ValueOf转换成的反射类型,能够经过Interface方法把它恢复成一个接口值,固然咱们能够直接将这个接口值转换成对应的原数据,例子以下所示:
定律三:修改反射对象的值
reflect.ValueOf函数返回的是一份值的拷贝,因此直接对这个值进行修改是无心义的,由于它不会更改原来的那个值。
要想修改原来的数值,须要借用指针的特性,进行修改,这里也就是定律三中提到的可设置性,经过Elem()来找到对应的原数据值。
例子以下所示:
4、反射的原理是什么?
反射的实现是以空接口做为基础的,能够说空的接口是反射实现的基石。空接口相似于C语言中的void*,它能够转换成任何类型的数值。
当咱们使用反射特性时,实际上用到的就是存储在 interface 变量中的和类型相关的信息,也就是常说的 <type, value>。
主要涉及到的数据结构和函数以下所示:
5、参考文档:
Go语言三大反射定律:https://blog.golang.org/laws-of-reflection
Go接口详解:https://zhuanlan.zhihu.com/p/27055513
深度解密Go语言之反射:https://zhuanlan.zhihu.com/p/64884660
灰子学技术:
本文分享自微信公众号 - 灰子学技术(huizixueguoxue)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。