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

  

 

posted @ 2020-02-16 00:17  顽强的allin  阅读(583)  评论(0编辑  收藏  举报