GO反射
一、反射介绍
- 反射是指在程序运行期对程序本身进行访问和修改的能力。程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分。在运行程序时,程序无法获取自身的信息。支持反射的语言可以在程序编译期将变量的反射信息,如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息,并且有能力修改它们。
- Go语言提供了一种机制在运行时更新和检查变量的值、调用变量的方法和变量支持的内在操作,但是在编译时并不知道这些变量的具体类型,这种机制被称为反射。反射也可以让我们将类型本身作为第一类的值类型处理。
二、反射中的Type和Kind
2.1 Type Type.Name()
type返回的是当前被反射对象的实际变量类型,如:
var name string = "abcd" |
在GO中type实际上指得是系统原生数据类型,如 int、string、bool、float32 等类型,以及使用 type 关键字定义的类型,这些类型的名称就是其类型本身的名称
2.2 Kind Type.Kind()
通俗意义上面来讲,Kind是GO中定义的一个对象属性的归属,用户可能会通过type关键词给类型起别名,而这个时候kind就反映了它实际真实的对象归属。
GO中内置的Kind类如下所示,其实它是一个枚举类型
type Kind uint |
如:
type Stu struct{ |
2.3、TypeOf() && ValueOf()
#todo
- TypeOf() && ValueOf() 区别
- 获取实际的Type类型,Type类型包含两部分一部分是实际类型(Name),一部分是所属GO中的类型(Kind)
三、内置Pair键值对
GO中的变量实际上分为两个部分,一个部分是变量类型,一个则是实际的Value。
- type:类型
- static type:静态类型,指当前已经确定的类型
- concrete type:动态类型,指在运行期间动态确定的值,比如一个interface的变量值为8.0,但是实际上在运行期间会确定为float。这个就是动态类型。
- value:指当前变量实际的值
四、reflect包
4.1、reflect.Type(通用方法所有类型均可使用)
4.1.1、Align() int && FieldAlign() int
- Align() int
返回该变量实际上在内存中分配的字节数 - FieldAlign() int
返回该类型在结构体中作为字段的字节数量
package main |
4.1.2、Method(int) int && MethodByName(string) (Method,bool)
- Method(int) int
- Method 这个方法返回类型方法集中的第 i 个方法。
- 如果 i 不在[0, NumMethod()]范围内,就会 panic。
- 对于一个**非接口类型 T 或 *T,返回的 Method 的 Type 和 Func**。
- fields 字段描述一个函数,它的第一个参数是接收方,而且只有导出的方法可以访问。
- 对于一个接口类型,返回的 Method 的 Type 字段给出的是方法签名,没有接收者,Func字段为nil。
- 方法是按字典序顺序排列的。
- NumMethod()
- NumMethod 返回使用 Method 可以访问的方法数量。
- NumMethod 只在接口类型的调用的时候,会对未导出方法进行计数。
- MethodByName(string) (Method,bool)
- MethodByName 返回类型中带有该名称的方法。
- 方法集和一个表示是否找到该方法的布尔值。
- 对于一个非接口类型 T 或 *T,返回的 Method 的 Type 和 Func。
- fields 字段描述一个函数,其第一个参数是接收方。
- 对于一个接口类型,返回的 Method 的 Type 字段给出的是方法签名,没有接收者,Func字段为nil。
示例代码:
package main |
4.1.3、PkgPath() string
- PkgPath 返回一个定义类型的包的路径,也就是导入路径,导入路径是唯一标识包的类型,如 “encoding/base64”。
- 如果类型是预先声明的(string, error)或者没有定义(T, struct{}, []int,或 A,其中 A 是一个非定义类型的别名),包的路径将是空字符串。(这里指匿名情况返回包路径为空
“”
)*
示例代码:
package main |
4.1.4、Size() uintptr
返回存储给定存储类型的值所需要的字节数量
func main() { |
4.1.5、String() string
返回该类型的字符串表示(打印对象全部字段)
func main() { |
4.1.6、类型比较
- Implements(u Type) bool
Implements 表示该类型是否实现了接口类型 u。 - AssignableTo(u Type) bool
AssignableTo 表示该类型的值是否可以分配给类型 u。 - ConvertibleTo(u Type) bool
ConvertibleTo 表示该类型的值是否可转换为 u 类型。 - Comparable() bool
Comparable 表示该类型的值是否具有可比性。
4.2、reflect.Type 专有方法
4.2.1、BIts() int
返回类型单位大小,类型非数字类型发生Panic
4.2.1、ChanDir() ChanDir
返回通道类型的方向,不是的话会Panic
4.2.2、IsVariadic() bool
返回当前是不是一个包含可变参数语法糖的函数
- t表示一个函数 func(x int, y … float64)
- t.NumIn() == 2
- t.In(0)是 “int” 的 reflect.Type 反射类型。
- t.In(1)是 “[]float64” 的 reflect.Type 反射类型。
- t.IsVariadic() == true
- 如果类型的 Kind 不是 Func.IsVariadic,IsVariadic 会 panic
4.2.3、Elem()
获取指针指向的对象的类型,例如:
type Stu struct { |
4.2.4、Fileld(i int) StructField && FieldByIndex(index []int) StructField && FieldByName(name string) (StructField, bool) && FieldByNameFunc(match func(string) bool) (StructField, bool)
- Fileld(i int) StructField
- Field 返回一个结构类型的第 i 个字段。
- 如果类型的 Kind 不是 Struct,就会 panic。
- 如果 i 不在 [0, NumField()] 范围内,也会 panic。
- FieldByIndex(index []int) StructField
- FieldByIndex 返回索引序列对应的嵌套字段。它相当于对每一个 index 调用 Field。
- 如果类型的 Kind 不是 Struct,就会 panic。
- FieldByName(name string) (StructField, bool)
- FieldByName 返回给定名称的结构字段和一个表示是否找到该字段的布尔值。
- FieldByNameFunc(match func(string) bool) (StructField, bool)
- FieldByNameFunc 返回一个能满足 match 函数的带有名称的 field 字段。布尔值表示是否找到。
- FieldByNameFunc 先在自己的结构体的字段里面查找,然后在任何嵌入结构中的字段中查找,按广度第一顺序搜索。最终停止在含有一个或多个能满足 match 函数的结构体中。如果在该深度上满足条件的有多个字段,这些字段相互取消,并且 FieldByNameFunc 返回没有匹配。
- 这种行为反映了 Go 在包含嵌入式字段的结构的情况下对名称查找的处理方式
typeUser.NumField()
|
4.2.5、In(i int) Type –Func && Out(i int) Type –Func.Out
In 返回函数类型的第 i 个输入参数的类型。
- 如果类型的 Kind 不是 Func 类型会 panic。
- 如果 i 不在 [0,NumIn())范围内会出现Panic
func main() { |
Out(i int) Type –Func.Out
- Out 返回一个函数类型的第 i 个输出参数的类型。
- 如果类型的类型不是 Func.Out,会 panic。
- 如果 i 不在 [0, NumOut()) 的范围内,会 panic。
func main() { |
4.2.6、Key() Type –Map
- Key 返回一个 map 类型的 key 类型。
- 如果类型的 Kind 不是 Map,会 panic。
func main() { |
4.2.7、Len() int –Arrary
- Len 返回一个数组类型的长度。
- 如果类型的 Kind 不是 Array,会 panic。
func main() { |
4.2.8、NumField() int –Struct
- NumField 返回一个结构类型的字段数目。
- 如果类型的 Kind 不是 Struct,会 panic。
示例如下:[[#4 2 4、Fileld i int StructField FieldByIndex index int StructField FieldByName name string StructField bool FieldByNameFunc match func string bool StructField bool]]
4.2.9、NumIn() int –Func.NumIn() && NumOut() int –Func.NumOut()
NumIn() int –Func.NumIn()
- NumIn 返回一个函数类型的输入参数数。
- 如果类型的 Kind 不是Func.NumIn(),会 panic。
NumOut() int –Func.NumOut()
- NumOut 返回一个函数类型的输出参数数。
- 如果类型的 Kind 不是 Func.NumOut(),会 panic。
func main() { |
4.2、reflect.Value
特殊说明的是 zero Value,zero Value 代表没有值。它的 IsValid() 方法返回 false,Kind() 方法返回 Invalid,String() 方法返回 “”,而剩下的所有其他方法均会 panic。
#todo