一.基本介绍
1.反射可以在运行时动态获取变量的各种信息,比如变量的类型,类别
2.如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)
3.通过反射,可以修改变量的值,可以调用关联的方法。
4.使用反射,需要 reflect 包
二.反射的应用场景
1.不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射
2.对结构体序列化时,如果结构体有指定Tag,也会使用到反射生成对应的字符串。
三.反射重要的函数和概念
1.reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型
2.reflect.ValueOf(变量名),获取变量的值,返回reflect.Value 是一个结构体类型,通过reflect.Value,可以获取到关于该变量的很多信息
3.变量、interface{}和reflect.Value是可以相互转换的。
四.基本操作
1.对基本数据类型进行反射的基本操作
2.对结构体进行反射的基本操作
五.反射注意事项和细节说明
1.reflect.Value.Kind,获取变量的类别,返回的是一个常量
2.Type是类型,Kind是类别,Type和Kind可能是相同的,也可能是不同的。
比如: var num int = 10 num的type是int ,kind 也是int
比如: var stu Student stu的Type是 包名.Student,kind是struct
3.通过反射可以在让变量在interface{}和reflect.value之间相互转换
4.使用反射的方法来获取变量的值(并返回对应的类型),要求数据类型匹配,比如x是int,那么就是应该使用reflect.value(x).int(),而不能使用其它的,否则保panic。
5.通过反射的来修改变量,注意当使用SetXxx方法来设置需要通过对应的指针类型来完成,这样才能改变传入的变量的值,同时需要使用到reflect.Value.Elem()方法
综合案例
1.
package main
import (
"fmt"
"reflect"
)
// 给一个变量 var v float64 = 1.2 使用反射来得到它的reflect.Value。
// 然后获取对应的Type,Kind和值,并将reflect.value转换成interfac{}
// 在将interfa{}转换成float64
func reflectTest(b interface{}) {
vvalue := reflect.ValueOf(b)
fmt.Println(vvalue)
vtype := reflect.TypeOf(b)
fmt.Println(vtype)
//获取 变量对应的kind
vkind := vvalue.Kind()
fmt.Println(vkind)
//将vvalue转成interface{}
vv := vvalue.Interface()
fmt.Printf("iv=%v iv type=%T \n", vv, vv)
//将interface{}通过断言转成需要的类型
stu, ok := vv.(float64)
if ok {
fmt.Println(stu)
}
}
func main() {
var v float64 = 1.2
reflectTest(v)
}
2.
修改后
fs的kind是string时是值传递,但是SetString(fs)需要fs的kind是ptr
PS:val.Elem()用于获取指针指向的变量