1.1.1. 一、反射的基本介绍。

1) 反射可以在运行时动态获取变量的各种信息, 比如变量的类型(type),类别(kind)。

2) 如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)。

3) 通过反射,可以修改变量的值,可以调用关联的方法。

4) 使用反射,需要reflect包 import “reflect”。

reflect包有2个重要的方法:

1、func TypeOf(i interface{}) Type,可以使用reflect.TypeOf(变量名) `,获取一个变量的Type类型的实例。Type是一个接口,里面有很多方法获取变量的信息(如:方法、字段等)。

2、func ValueOf(i interface{}) Value,可以使用reflect.ValueOf(变量名),获取一个变量的Value类型的实例。Value是一个结构体,里面有很多方法获取变量的信息(如:方法、字段等),也可以执行变量的方法。

3、变量、Type类型 、Value类型的实例,他们3个可以相互装换。可以通过Type类型实例获取到Value类型实例,反之亦然。具体看文档。

  • valueRef :=reflect.ValueOf(变量名),得到变量的Value类型实例valueRef。
  • valueRef.
  • 例子1:通过变量,使用反射创建一个新的实例。

下面的转换:Student实例-->reflect.Value实例--->新的Student实例。

type Student struct {
    Name string
    Age int
}

// Student实例-->reflect.Value--->新的Student实例
func testReflect()  {
    stu := Student{
        Name:"张三",
        Age:16,
    }
    //stu变量通过反射,得到reflect.Value类型实例stuValue
    var stuValue reflect.Value = reflect.ValueOf(stu)

    //stuValue 调用Interface()方法,把stu的值转换为接口返回。
    iStu := stuValue.Interface()

    // 类型断言,把接口转为Student的实例。
    stu2,ok:= iStu.(Student)
    if ok {
        // 原来的地址=0xc000058400,值={张三 16}
        fmt.Printf("原来的地址=%p,值=%v \n",&stu,stu)

        // from reflect 地址=0xc000058440,值={张三 16}
        fmt.Printf("from reflect 地址=%p,值=%v \n",&stu2,stu2)
    }
}

func main() {
    testReflect()
}

例子中有3步:

  1. var stuValue reflect.Value = reflect.ValueOf(stu),stu变量通过反射,得到reflect.Value类型实例stuValue。
  2. iStu := stuValue.Interface(),stuValue 调用Interface()方法,把stu的值转换为接口返回。
  3. stu2,ok:= iStu.(Student),类型断言,把接口转为Student的实例。
  4. stu2 的地址和 stu 的地址不一样,表示它们是2个不同的实例。
  • 例子2:int类型,通过变量,使用反射创建一个新的实例。

转换过程:int实例-->reflect.Value实例--->新的int实例。

func testReflect2()  {
    num := 90
    var numValue reflect.Value = reflect.ValueOf(num)
    iNum := numValue.Interface()
    num2,ok:= iNum.(int)
    if ok {
        // 原来的地址=0xc000062080,值=90
        fmt.Printf("原来的地址=%p,值=%v \n",&num,num)
        //from reflect 地址=0xc000062090,值=90
        fmt.Printf("from reflect 地址=%p,值=%v \n",&num2,num2)
    }
}

func main() {
    testReflect2()
}
  • 例子3:反射获取变量的值,做加法。

//反射做加法
func testReflect()  {

    var b int = 30
    //反射获取reflect.Type
    rType := reflect.TypeOf(b)
    fmt.Println("b的类型=",rType) //b的类型= int

    //反射获取 reflect.Value
    rVal := reflect.ValueOf(b)
    fmt.Println("b的值=",rVal) //b的值= 30

    //rVal.Int(),如果rVal的Kind不是Int、Int8、Int16、Int32、Int64会panic
    num := rVal.Int() + 12
    fmt.Println("b的值+12=",num) //b的值+12= 42
}

func main() {
    testReflect()
}

说明:rVal.Int() 返回rVal的int值。如果rVal的Kind不是Int、Int8、Int16、Int32、Int64会panic,也就是变量b的类型不是Int、Int8、Int16、Int32、Int64会panic。

使用这个方式取值,数据类型不匹配会panic。还可以取下面的值:其他的看文档。

1.1.2. 二、反射的类别(kind)。

  • Type 和 Kind 的区别:Type 是类型, Kind 是类别, Type 和 Kind 可能是相同的,也可能是不同的。

比如:var num int = 10。num 的 Type 是 int, Kind 也 是 int。

比如:var stu Student。stu 的 Type 是:包名.Student, Kind 是 struct。

  • Kind是常量。可以通过reflect.Struct、reflect.Int、reflect.Float32等获取。
type Student struct {
    Name string
    Age int
}
func testReflect()  {

    fmt.Println(reflect.Int) // int
    fmt.Println(reflect.Float32) //float32
    fmt.Println(reflect.Struct) //struct

    stu := Student{
        Name:"张三",
        Age:16,
    }
    rType := reflect.TypeOf(stu)
    rVal := reflect.ValueOf(stu)
    fmt.Println("rkind =",rType.Kind()) //rkind = struct
    fmt.Println("vkind =",rVal.Kind()) //vkind = struct
    fmt.Println(reflect.TypeOf(16).Kind()) //int
}

func main() {
    testReflect()
}

通过反射可以获取变量的kind:

  • rType := reflect.TypeOf(stu)
  • rVal := reflect.ValueOf(stu)

三、用反射修改变量的值。

results matching ""

    No results matching ""