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.
下面的转换: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步:
var stuValue reflect.Value = reflect.ValueOf(stu)
,stu变量通过反射,得到reflect.Value类型实例stuValue。iStu := stuValue.Interface()
,stuValue 调用Interface()方法,把stu的值转换为接口返回。stu2,ok:= iStu.(Student)
,类型断言,把接口转为Student的实例。- stu2 的地址和 stu 的地址不一样,表示它们是2个不同的实例。
转换过程: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()
}
//反射做加法
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)
三、用反射修改变量的值。