![ffbf67fdb07e3d4a8caabba5c87e57ac.png](https://i-blog.csdnimg.cn/blog_migrate/903311a5d417051cce9ce275213fdc3d.jpeg)
学了好长一段时间Go了, 最近准备写一系列文章来总结学习的经验,第一篇是反射。
最开始接触到反射是在Java中,当时的理解是:反射可以在运行时来加载编译好的字节码,而不需要进行编译的过程,非常的灵活。在Go中也是如此:如果我们想要使用在编写程序时不存在的信息,例如变量;或者将文件或网络请求中的数据映射到变量中,在这些情况下,就需要使用反射。 Reflection使我们能够在运行时检查类型,检查、修改和创建变量,函数和结构等,非常强大。
在Go中的反射围绕三个概念构建:Type,Kind和Value,在Go中主要使用标准库中的reflect包来实现调用反射的各种功能。
基本用法
首先让我们来看看reflect.Type。可以使用反射来获取变量var的类型,函数调用varType := reflect.TypeOf(var), 这将返回一个reflect.Type类型的变量,该变量包含有关定义传入变量的类型的各种信息的方法。
第一个方法是Name(),它会返回类型的名称,某些类型(如slice或pointer)没有名称,此方法返回空字符串。
下一个方法是Kind(),非常有用。kind是由 slice,map,pointer, struct,inerface,string,array,func,int或其他一些基本类型构成。Kind() 和Name() 之间的差异可能很难理解,但可以理解为:如果定义一个名为Foo的struct,则kind() 返回struct,Name() 返回Foo。
举个简单的例子吧:
type User struct {
Name string
Age int
}
user := User{
"jack",
20,
}
userType := reflect.TypeOf(user)
fmt.Println(userType.Name())
fmt.Println(userType.Kind())
可以看到打印的结果分别是:User, struct。
使用反射时需要注意的一件事:反射包中的所有内容都假定用户知道自己在做什么,如果使用不当,许多函数和方法调用都会造成panic。例如,如果在reflect.Type上调用一个方法,该方法与当前类型不同的类型相关联,那么程序将会崩溃。一种不错的解决方案是,始终记得使用Kind() 来判断反射值的类型
如果变量是pointer,map,slice,channel或array,则可以使用 varType.Elem() 找到包含的类型。
如果变量是struct,则可以使用反射来获取结构中的字段数,并获取reflect.StructField结构中包含的每个字段的结构。