这是我参与「第三届青训营 -后端场」笔记创作活动的的第三篇笔记。
什么是反射
反射是指在程序运行期对程序本身进行访问和修改的能力,程序在编译时变量被转换为内存地址,变量名不会被编译器写入到可执行部分,在运行程序时程序无法获取自身的信息。
获取类型信息
- 通过Reflect.TypeOf()函数,我们可以从一个任何非接口类型的值创建一个reflect.Type值。该值表示此非接口的类型。通过此值,我们可以得到很多此非接口类型的信息。
- 同时也可以将一个接口值传递给一个reflect.TypeOf()函数调用,但此调用将返回一个此接口值的动态类型的reflect.Type值。
唯一参数:interface{},reflect.TypeOf函数将总是返回一个表示着此唯一接口参数值的动态类型的reflect.Type值。
看如下代码:
func main() {
var x int
typeX := reflect.TypeOf(x)
fmt.Println(typeX.Name(), typeX.Kind())
}
输出 int int
上述代码先定义了一个int类型变量,然后获取变量x的类型对象,类型为reflect.Type()。
但是Type和Kind的区别又是什么呢?
- Type表示的是原生数据类型,如int、bool以及type定义关键字等,这些类型的名称就是类型本身的名称。
- Kind指的是对象归属的品种。
看如下代码:
type Num int
const (
One Num = 1
)
func main() {
type dog struct {
}
typeDog := reflect.TypeOf(dog{})
fmt.Println(typeDog.Name(), typeDog.Kind())
typeOne := reflect.TypeOf(One)
fmt.Println(typeOne.Name(), typeOne.Kind())
}
输出结果:
dog struct
Num int
获取值信息
我们将一个接口值传递给一个reflect.ValueOf函数调用,此调用返回的是代表着此接口值的动态值的一个reflect.Value值,我们必须通过间接途径获得一个表示一个接口值的reflect.Value值。
func main() {
var x int = 24
valueX := reflect.ValueOf(x)
x1 := valueX.Interface().(int)
x2 := int(valueX.Int())
fmt.Printf("x1: %v\n", x1)
fmt.Printf("x2: %v\n", x2)
}
- 上述例子中获取x1是通过类型断言转为int再赋值给x1
这里打断一下,什么是类型断言? 语法如下:
value, ok := x.(T)
- x表示一个接口的类型,T表示一个具体的类型。
- 这个表达式会返回x的value,和一个ok,也就是判断x是否为T类型。
- 如果返回类型断言失败,不传第二个值会引起panic。
- 获取x2是通过Int方法,以int64去除,再通过强制类型转换赋值(注意Go中只有强制类型转换)。