golang之反射
反射基本介绍
1)反射可以在运行时动态获取变量的各种信息,比如变量的类型(type),类别(kind)
2)如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段,方法)
3)通过反射,可以修改变量的值,可以调用关联的方法
4)使用反射,需要 import ("reflect")
反射重要的函数和概念
1)reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型
2)reflect.ValueOf(变量名),获取变量的值,返回reflect.Value类型,reflect.Value是一个结构体类型。通过reflect.Value,可以获取到关于该变量的很多信息
3)变量、interface{}和reflect.Value是可以相互转换的,这点在实际开发中,会经常使用到。
interface{} ——> reflect.Value:
rVal := reflect.ValueOf(b)
reflect.Value ——> interface{}:
iVal := rVal.Interface()
interface{} ——> 原来的变量(类型断言):
v := iVal.(Stu)
快速入门案例
对基本数据类型
func reflectTest01(b interface{}) { // 1.获取到reflect.Type rType := reflect.TypeOf(b) fmt.Println("rType = ", rType) // 2.获取到reflect.Value rVal := reflect.ValueOf(b) fmt.Printf("rVal = %v, rVal = %T\n", rVal, rVal) n2 := 2 + rVal.Int() fmt.Println("n2 = ", n2) // 将 rVal 转换成 interface{} iV := rVal.Interface() // 通过类型断言转成需要的类型 num2 := iV.(int) fmt.Printf("num2 = %v, num2 = %T\n", num2, num2) }
对结构体
func reflectTest02(b interface{}) { rType := reflect.TypeOf(b) fmt.Println(rType) rVal := reflect.ValueOf(b) iV := rVal.Interface() fmt.Printf("iv=%v\tiv type=%T\n", iV, iV) stu, ok := iV.(Student) if ok { fmt.Println("stu.Name=", stu.Name) } }
反射的注意事项
1)reflect.Value.kind,获取变量的类别,返回的是一个常量
2)Type是类型,kind是类别,可能相同,也可能不相同
比如:var num int = 10 num的Type是int,Kind也是int
var stu Student stu的Type是包名.Student,Kind是struct
3)通过反射可以让变量在interface{}和Reflect.Value之间相互转换:
变量 <——> interface{} <——> reflect.Value
4)使用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,比如x是int,那么就应该使用reflect.Value(x).Int(),而不能使用其它的,否则报painc
5)通过反射来修改变量,注意当使用SetXxx方法来设置需要通过对应的指针类型来完成,这样才能改变传入的变量的值,同时需要使用到reflect.Value.Elem()方法
func reflectTest(b interface{}) { rVal := reflect.ValueOf(b) rVal.Elem().SetInt(20) } func main() { var num = 10 reflectTest(&num) fmt.Println(num) }
6)reflect.Elem()的理解:
var i int = 3 var p *int = &i fmt.Println(p, i) v := reflect.ValueOf(p) fmt.Println(v) fmt.Println(v.Interface()) // This is the p pointer fmt.Println(v.Elem().Interface()) // This is i's value: 3