go语言有没有反射
这篇文章主要讲解了“go语言有没有反射”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“go语言有没有反射”吧!
go语言有反射。Go语言提供了一种机制在运行时更新和检查变量的值、调用变量的方法和变量支持的内在操作,但是在编译时并不知道这些变量的具体类型,这种机制被称为反射。Go语言中的反射是由reflect包提供支持的,它定义了两个重要的类型Type和Value任意接口值在反射中都可以理解为由reflect.Type和reflect.Value两部分组成。
Go语言提供了一种机制在运行时更新和检查变量的值、调用变量的方法和变量支持的内在操作,但是在编译时并不知道这些变量的具体类型,这种机制被称为反射。反射也可以让我们将类型本身作为第一类的值类型处理。
go语言中的反射
反射是指在程序运行期对程序本身进行访问和修改的能力,程序在编译时变量被转换为内存地址,变量名不会被编译器写入到可执行部分,在运行程序时程序无法获取自身的信息。
支持反射的语言可以在程序编译期将变量的反射信息,如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息,并且有能力修改它们。
C/C++语言没有支持反射功能,只能通过 typeid 提供非常弱化的程序运行时类型信息;Java、C# 等语言都支持完整的反射功能;Lua、JavaScript 类动态语言,由于其本身的语法特性就可以让代码在运行期访问程序自身的值和类型信息,因此不需要反射系统。
Go语言程序的反射系统无法获取到一个可执行文件空间中或者是一个包中的所有类型信息,需要配合使用标准库中对应的词法、语法解析器和抽象语法树(AST)对源码进行扫描后获得这些信息。
Go语言提供了 reflect 包来访问程序的反射信息。
reflect 包
Go语言中的反射是由 reflect 包提供支持的,它定义了两个重要的类型 Type 和 Value 任意接口值在反射中都可以理解为由 reflect.Type 和 reflect.Value 两部分组成,并且 reflect 包提供了 reflect.TypeOf 和 reflect.ValueOf 两个函数来获取任意对象的 Value 和 Type。
反射的类型对象(reflect.Type)
在Go语言程序中,使用 reflect.TypeOf() 函数可以获得任意值的类型对象(reflect.Type),程序通过类型对象可以访问任意值的类型信息,下面通过示例来理解获取类型对象的过程:
运行结果如下:packagemainimport("fmt""reflect")funcmain(){varainttypeOfA:=reflect.TypeOf(a)fmt.Println(typeOfA.Name(),typeOfA.Kind())}
代码说明如下:
第 9 行,定义一个 int 类型的变量。
第 10 行,通过 reflect.TypeOf() 取得变量 a 的类型对象 typeOfA,类型为 reflect.Type()。
第 11 行中,通过 typeOfA 类型对象的成员函数,可以分别获取到 typeOfA 变量的类型名为 int,种类(Kind)为 int。
反射的类型(Type)与种类(Kind)
在使用反射时,需要首先理解类型(Type)和种类(Kind)的区别。编程中,使用最多的是类型,但在反射中,当需要区分一个大品种的类型时,就会用到种类(Kind)。例如需要统一判断类型中的指针时,使用种类(Kind)信息就较为方便。
1) 反射种类(Kind)的定义
Go语言程序中的类型(Type)指的是系统原生数据类型,如 int、string、bool、float32 等类型,以及使用 type 关键字定义的类型,这些类型的名称就是其类型本身的名称。例如使用 type A struct{} 定义结构体时,A 就是 struct{} 的类型。
种类(Kind)指的是对象归属的品种,在 reflect 包中有如下定义:
Map、Slice、Chan 属于引用类型,使用起来类似于指针,但是在种类常量定义中仍然属于独立的种类,不属于 Ptr。type A struct{} 定义的结构体属于 Struct 种类,*A 属于 Ptr。typeKinduintconst(InvalidKind=iota//非法类型Bool//布尔型Int//有符号整型Int8//有符号8位整型Int16//有符号16位整型Int32//有符号32位整型Int64//有符号64位整型Uint//无符号整型Uint8//无符号8位整型Uint16//无符号16位整型Uint32//无符号32位整型Uint64//无符号64位整型Uintptr//指针Float32//单精度浮点数Float64//双精度浮点数 plex64//64位复数类型 plex128//128位复数类型Array//数组Chan//通道Func//函数Interface//接口Map//映射Ptr//指针Slice//切片String//字符串Struct//结构体UnsafePointer//底层指针)
2) 从类型对象中获取类型名称和种类
Go语言中的类型名称对应的反射获取方法是 reflect.Type 中的 Name() 方法,返回表示类型名称的字符串;类型归属的种类(Kind)使用的是 reflect.Type 中的 Kind() 方法,返回 reflect.Kind 类型的常量。
下面的代码中会对常量和结构体进行类型信息获取。
运行结果如下:packagemainimport("fmt""reflect")//定义一个Enum类型typeEnumintconst(ZeroEnum=0)funcmain(){//声明一个空结构体typecatstruct{}//获取结构体实例的反射类型对象typeOfCat:=reflect.TypeOf(cat{})//显示反射类型对象的名称和种类fmt.Println(typeOfCat.Name(),typeOfCat.Kind())//获取Zero常量的反射类型对象typeOfA:=reflect.TypeOf(Zero)//显示反射类型对象的名称和种类fmt.Println(typeOfA.Name(),typeOfA.Kind())}
代码说明如下:
第 17 行,声明结构体类型 cat。
第 20 行,将 cat 实例化,并且使用 reflect.TypeOf() 获取被实例化后的 cat 的反射类型对象。
第 22 行,输出 cat 的类型名称和种类,类型名称就是 cat,而 cat 属于一种结构体种类,因此种类为 struct。
第 24 行,Zero 是一个 Enum 类型的常量。这个 Enum 类型在第 9 行声明,第 12 行声明了常量。如没有常量也不能创建实例,通过 reflect.TypeOf() 直接获取反射类型对象。
第 26 行,输出 Zero 对应的类型对象的类型名和种类。
指针与指针指向的元素
Go语言程序中对指针获取反射对象时,可以通过 reflect.Elem() 方法获取这个指针指向的元素类型,这个获取过程被称为取元素,等效于对指针类型变量做了一个*操作,代码如下:
运行结果如下:packagemainimport("fmt""reflect")funcmain(){//声明一个空结构体typecatstruct{}//创建cat的实例ins:=&cat{}//获取结构体实例的反射类型对象typeOfCat:=reflect.TypeOf(ins)//显示反射类型对象的名称和种类fmt.Printf("name:'%v'kind:'%v'\n",typeOfCat.Name(),typeOfCat.Kind())//取类型的元素typeOfCat=typeOfCat.Elem()//显示反射类型对象的名称和种类fmt.Printf("elementname:'%v',elementkind:'%v'\n",typeOfCat.Name(),typeOfCat.Kind())}
代码说明如下:
第 13 行,创建了 cat 结构体的实例,ins 是一个 *cat 类型的指针变量。
第 15 行,对指针变量获取反射类型信息。
第 17 行,输出指针变量的类型名称和种类。Go语言的反射中对所有指针变量的种类都是 Ptr,但需要注意的是,指针变量的类型名称是空,不是 *cat。
第 19 行,取指针类型的元素类型,也就是 cat 类型。这个操作不可逆,不可以通过一个非指针类型获取它的指针类型。
第 21 行,输出指针变量指向元素的类型名称和种类,得到了 cat 的类型名称(cat)和种类(struct)。
感谢各位的阅读,以上就是“go语言有没有反射”的内容了,经过本文的学习后,相信大家对go语言有没有反射这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是主机评测网,小编将为大家推送更多相关知识点的文章,欢迎关注!
上一篇:nodejs事件循环是什么