875 字
4 分钟
Go 语言学习笔记 -第12章
Go 语言学习笔记 -第12章
反射
基本介绍
1、反射运行在运行时动态 获取变量的各种信息,包括变量的类型、类别
2、如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段,方法)
3、通过反射,可以修改变量的值,可以调用关联的方法
4、使用反射,需要import reflect
应用场景
1、不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口 这种需要对函数或者方法反射,比如
func bridge(funcPtr interface{}, args....interface{})
第一个参数funcPtr以接口的形式传入函数指针,函数参数args以可变参数的形式传入bridge函数中可以用反射来动态执行funcPtr函数2、结构体序列化 ,如果结构体有指定tag, 也可以使用反射生成对应的字符串
type Monster struct { Name string `json:"name"` Age int `json:"age"`}3、重要函数
reflect.TypeOf - 获取变量的类型reflect.ValueOf - 获取变量的值例子:
package main
import ( "fmt" "reflect")
func reflectTest01(b interface{}) {
//通过反射获取变量的type, kind,value //1.获取reflect.Type rType := reflect.TypeOf(b) fmt.Println("rType=", rType) //int
//2.获取reflect.Value rVal := reflect.ValueOf(b) // n1 := 10 // n2 := 2 + n1
// n2 := 2 + rVal //invalid operation: 2 + rVal (mismatched types int and reflect.Value)
n2 := 2 + rVal.Int() fmt.Println("rVal=", rVal) //100 fmt.Println("n2=", n2) //102 fmt.Printf("rVal=%v, rval type=%T\n", rVal, rVal) //rVal=100, rval type=reflect.Value
//将rval转成interface{} iV := rVal.Interface() //通过断言转成需要的类型 num2 := iV.(int) fmt.Println("num2=", num2)
}
type Student struct { Name string Age int}
type Monster struct { Name string Age int}
func main() {
stu := Student{ Name: "tom", Age: 20, }
reflectTest01(stu)
}package main
import ( "fmt" "reflect")
func reflectTest02(b interface{}) {
//通过反射获取变量的type, kind,value //1.获取reflect.Type rType := reflect.TypeOf(b) fmt.Println("rType=", rType) //rType= main.Student
//2.获取reflect.Value rVal := reflect.ValueOf(b)
//将rval转成interface{} iV := rVal.Interface() fmt.Printf("iV=%v, iV=%T\n", iV, iV) //iV={tom 20}, iV=main.Student
// fmt.Printf("name=%v", iV.Name) //iV.Name undefined (type interface {} is interface with no methods)
//通过断言转成需要的类型 stu, ok := iV.(Student) if ok { fmt.Printf("stu.Name=%v", stu.Name) }
}
type Student struct { Name string Age int}
type Monster struct { Name string Age int}
func main() {
stu := Student{ Name: "tom", Age: 20, }
reflectTest02(stu)
}反射细节:
1、reflect.Value.Kind 获取变量的类别
//1.获取reflect.TyperType := reflect.TypeOf(b)fmt.Println("rType=", rType) //rType= main.Student
//2.获取reflect.ValuerVal := reflect.ValueOf(b)
//3.获取reflect.kind// rKind := rVal.Kind()rKind := rType.Kind()fmt.Println("rKind=", rKind)2、Type是类型,Kind是类别 Type和Kind可能是相同的,也可能是不同的
如:
var num int = 10 num 的Type 是int, Kind也是intvar stu Student stu的Type是包名.Student, Kind是struct3、通过反射可以让变量在interface{} 和reflect.value之间相互转换
4、使用反射的方式来获取变量的值 要求数据类型匹配
如果x是int,那么就应该使用reflect.Value(x).Int(),而不能使用其他的
5、通过反射来修改变量,当使用SetXX方法来设置需要通过对应的指针类型 来完成,这样才能改变传入的变量的值,同时需要使用reflect.Value.Elem方法
6.reflect.Value.Elem()怎么理解:
package main
import ( "fmt" "reflect")
func reflectTest(b interface{}) {
//获取reflect.Value rVal := reflect.ValueOf(b) rKind := rVal.Kind() fmt.Printf("rval kind=%v\n", rKind) //ptr
//改变值 rVal.Elem().SetInt(20) //这里elem很重要
//可以这样理解Val.Elem() // num := 9 // ptr *int = &num // num2 := *ptr
}
type Student struct { Name string Age int}
type Monster struct { Name string Age int}
func main() {
var num int = 10
reflectTest(&num) // reflectTest(num) fmt.Println("num=", num)
} Go 语言学习笔记 -第12章
https://blog.zhequtao.com/posts/golang/go-learning/学习笔记-go/第12章/