1.反射细节
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。
区别理解:Kind指的是在go语言里你的这个变量具体是属于哪一种大类,比如stu属于struct,本质是一个常量,如果是nil表示非法分类。
Type指的是一个变量具体属于哪一类,比如stu属于学生结构体Student
package main
import (
"fmt"
"reflect"
)
func reflectTest01(b interface{}) {
//通过反射获取的传入的变量的 type , kind,值
//感觉有点像包装一个类型结构体然后绑定String()方法输出内部数值。
//实际类型是一个包装类型,但是输出内容的都是内部存储类型。
//1。先获取到 reflect.Type
rType := reflect.TypeOf(b)
fmt.Println(rType) //真正类型是reflect.Type,但是输出会自动变成内部存储类型的实际类型int
//2。先获取到 reflect.Value
rVal := reflect.ValueOf(b)
//报错cannot convert 2 (untyped int constant) to type struct{typ *reflect.rtype,
//说明实际不是int类型而是reflect.Value
//所以Value提供了很多方法去修改或者读取内部的值
//n2 := 2 + rVal
n2 := 2 + rVal.Int() //读取内部Int值
fmt.Println(n2)
fmt.Println(rVal) //真正类型是reflect.Value,但是输出会自动变成内部存储类型的实际值
fmt.Printf("rVal内部数值:%v,rVal真正类型:%T\n", rVal, rVal)
//3.将rVal转成interface{}
iV := rVal.Interface() //把内部值按空接口类型输出
//通过断言把interface{}转成需要的类型
n3 := iV.(int)
fmt.Println("n3=", n3)
}
type Student struct {
Name string
Age int
}
// 对结构体反射
func reflectTest02(b interface{}) {
//1。先获取到 reflect.Type
rType := reflect.TypeOf(b)
fmt.Println(rType) //真正类型是reflect.Type,但是输出会自动变成内部存储类型的实际类型int
//2。先获取到 reflect.Value
rVal := reflect.ValueOf(b)
//获取对应Kind,从Value和Type都可以,一模一样
kind1 := rVal.Kind()
kind2 := rType.Kind()
fmt.Printf("kind1内部数值:%v,kind1真正类型:%T\n", kind1, kind1)
fmt.Printf("kind2内部数值:%v,kind2真正类型:%T\n", kind2, kind2)
//3.将rVal转成interface{}
iV := rVal.Interface() //把内部值按空接口类型输出
fmt.Printf("iV 内部数值:%v,iV 真正类型:%T\n", iV, iV) //运行看实际类型,所以输出的是Student类型
//虽然运行输出可以,但是想调用Student内容是不行的,编译不知道底层实际类型,所以需要通过断言把interface{}转成需要的类型
stu, ok := iV.(Student) //也可以switch
if ok {
fmt.Println("stu.Name=", stu.Name)
}
}
func main() {
演示对(基本数据类型、interface{(}、reflect.value)进行反射的基本操作
//1.定义int
// var num int = 100
// reflectTest01(num)
//2.定义结构体
stu := Student{
Name: "tom",
Age: 20,
}
reflectTest02(stu)
}
3. 变量和空接口和Reflect.Value可以相互转换
4.Reflect.Value调用取基本类型的函数要求类型匹配,取结构体类型只能先断言再用,没有提供函数
5.通过反射的函数来修改变量
注意当使用setXxx方法来设置需要通过对应的指针类型来完成,这样才能改变传入的变量的值,同时需要使用到reflect.Value.Elem()方法
288_尚硅谷_反射的注意事项和细节(2)_哔哩哔哩_bilibili
注意:在反射函数里修改值的时候想要传指针,但是传指针就导致函数里Reflect.Value封装了指针类型的Value,会导致后续无法进行某些操作。
所以需要Elem方法,把一个封装了指针或者接口的Value转换成封装了它们指向(承载)的值的一个封装的Value