参考资料
Go语言圣经 - 十二章
反射的基本介绍
Go语言提供了一种机制在运行时更新变量和检查它们的值、调用它们的方法和它们支持的内在操作,但是在编译时并不知道这些变量的具体类型,这种机制被称为反射。
两个基础包使用反射的例子:
- fmt包提供的字符串格式化功能
- encoding/json 和 encoding/xml 提供的针对特定协议解码的功能
为什么需要反射
有时候我们需要编写一个函数能够处理一类并不满足普通公共接口的类型的值,也可能是因为它们并没有确定的表达方式,或者是在我们设计函数的时候还不知道这些类型可能还不存在,各种情况都有可能。
reflect.Type 和 reflect.Value
- reflect.Type - 表示一个go类型
Str := "hello world"
var rType reflect.Type
rType = reflect.TypeOf(Str) // 返回类型
fmt.Printf("reflect.TypeOf(Str): %s\n", rType) // reflect.TypeOf(Str): string
补充知识:将一个具体的值转化为接口类型会有一个隐式的接口转换操作,它会创建一个包含两个信息的接口值:操作数的动态类型 和 它的动态的值
reflect.Type接口是满足fmt.Stringer接口的,因为打印动态类型值对于调试和日志是有帮助的,%T也可以打印出类型
fmt.Printf("str type:%T\n",Str) //str type:string
- reflect.Value - 可以持有任意一个类型的值
Str := "hello world"
var rValue reflect.Value
rValue = reflect.ValueOf(Str)
fmt.Printf("reflect.ValueOf(Str): %#v\n", rValue) // "hello world"
t := rValue.Type()
fmt.Println(t.String())
- reflect.Value中的Kind()方法
Kinds直接返回底层的数据类型:Bool、string和所有的数字类型的基础类型;Array和Struct对应的聚合类型;Chan、Func、Ptr、Slice和Map对应的引用类型;接口类型;还有表示空值的无效类型(空的reflect.Value 对应 Invalid无效类型)
var Str1 MyString
Str1 = "hello world"
rValue1 := reflect.ValueOf(Str1)
var rKind reflect.Kind
rKind = rValue1.Kind() // 返回底层数据类型
fmt.Printf("reflect.ValueOf(Str1).Type(): %s\n", rValue1.Type()) // main.String
fmt.Printf("reflect.ValueOf(Str1).Kind(): %s\n", rKind) // string