本人从事Go语言开发多年,目前主要从事云计算相关开发。
写本公众号的目的主要是对自己的过往知识进行梳理,也希望可以帮助大家学习~
后续会推出Go语言源码学习系列和web开发系列等,欢迎大家关注。
思维逻辑图如下:
下面我们从以上三个方面对 反射 进行相应的介绍
前面我们提到,通过反射机制,我们可以获得变量相关的值、类型、方法等信息;这一部分我们介绍首先获取类型信息
Golang中,通过调用reflect包中的TypeOf()获取变量的类型信息
我们通过一个简单的例子来看一下TypeOf函数的使用:
结果如下:
下面我们通过源码进一步分析:
1)TypeOf函数
TypeOf函数将传入的任何类型转换为其反射类型对象:Type类型,而Type被定义为一种接口:
而在Type接口里定义了我们获取变量相关信息的一些方法:
所以,当我们将任意类型的变量转换为Type接口类型后,可以调用其相关的函数实现对目标信息的获取。本示例中,我们想获得类型信息,所以调用其Kind函数便可获取到,其他相关方法我们后续有部分涉及,大家有兴趣的话可以都尝试一下
2) 本示例中,我们调用了Kind函数获取类型信息,那么作为了解,Golang中定义了哪些类型呢?源码中定义如下:
如上所示,共计27种类型定义
示例:我们进一步以获取某个结构体的字段的类型值为例,对相关的方法进行演示:
结果如下:
分析:如上,我们通过TypeOf函数将结构体对象转为Type对象,再调用FieldByName,NumField以及Field等相关函数得到字段的相关信息,而字段相关的信息保存在StructField结构体里,如下:
该函数将任意类型的输入转换为其反射值对象,Value被定义为结构体
该结构体定义了许多值相关的方法,比如我们本例中调用的Int()方法
通过源码注释,我们知道:当v的类型为Int类型时,返回其值,如果不是Int类型则panic。还有很多其他类似的方法,大家也可以自己去实践一下
下面我们进一步通过一个例子演示:
结果如下:
panic的原因如下:Interface方法不能被非导出字段调用
反射三定律其实在上文的介绍中,我们其实已经在使用了,这里单独抽离进行归纳介绍
定律1:接口到反射类型的转换
其实,接口到反射类型的转换,就是我们上文介绍的两个函数:reflect.TypeOf()和reflect.ValueOf(),它俩会将接口类型变量转换为反射类型变量
分别如下:
示例如下:
结果如下:
定律2:反射到接口类型的转换
定律2是说:我们可以将反射类型变量再转换为接口类型,而使用的方法就是上文中我们调用的Interface()方法
结果如下:
定律3:修改反射类型对象
定律3是说:我们可以通过反射对变量值进行修改,但是变量值必须为可设的(CanSet):可寻址(CanAddr),可导出(首字母大写,不可匿名)
示例如下:
结果如下:
分析:对获取的反射类型对象进一步通过Elem获取其变量的值,然后对变量的值进行操作,由结果第一、二行对比可知,Elem的作用相当于取指针类型变量的元素
总结:本篇主要介绍了反射机制,反射由于其灵活性广泛应用于通用框架,然而鱼与熊掌不可兼得,带来的是效率上的损失,所以关于反射的使用要综合考量,最后,通过一个基准测试的例子进一步说明效率上反射的损失,也为下一篇做铺垫
执行方式:go test -bench=. 结果如下:
分析:由最后一列可知,效率上变得很差
到此关于Golang文件操作相关内容的分享就结束了~
此篇为Go语言基础系列分享第十二篇,欢迎大家关注本公众号《Go开发与计算机技术》,Go语言基础系列学习不迷路。