Go中的反射 | 青训营笔记

74 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第三篇笔记。

什么是反射

反射是指在程序运行期对程序本身进行访问和修改的能力,程序在编译时变量被转换为内存地址,变量名不会被编译器写入到可执行部分,在运行程序时程序无法获取自身的信息。

获取类型信息

  • 通过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)

}
  1. 上述例子中获取x1是通过类型断言转为int再赋值给x1

这里打断一下,什么是类型断言? 语法如下:

value, ok := x.(T)

  • x表示一个接口的类型,T表示一个具体的类型。
  • 这个表达式会返回x的value,和一个ok,也就是判断x是否为T类型。
  • 如果返回类型断言失败,不传第二个值会引起panic。
  1. 获取x2是通过Int方法,以int64去除,再通过强制类型转换赋值(注意Go中只有强制类型转换)。