go反射
反射 基本介绍 应用场景 基本使用 结构体 注意 练习 最佳实践 遍历结构体的方法,调用接头体的方法,获取结构体的标签
反射
基本介绍
反射可以在运行时动态获取变量的各种信息,比如变量的类型(type)、类别(kind) 如果是结构体变量,可以获取到结构体本身的信息(包括结构体的字段、方法) 通过反射,可以修改变量的值,可以调用关联的方法 使用反射,需要import(“reflect”) 示意图
应用场景
reflect.TypeOf(变量名) 获取变量的类型,返回reflect.Type类型 reflect.ValueOf(变量名)获取变量的值,返回reflect.Value 是一个结构体类型,通过reflect.Value,可以获取该变量的很多信息 变量、interface{} 和 reflect.Value 是可以相互转换的,这点在实际开发中经常会用到
基本使用
func reflectTest01 ( b interface { } ) {
rTyp := reflect. TypeOf ( b)
fmt. Println ( "TypeOf" , rTyp)
fmt. Printf ( "TypeOf Type %T \n" , rTyp)
value := reflect. ValueOf ( b)
fmt. Println ( "ValueOf" , value)
fmt. Printf ( "ValueOf %T\n" , value)
fmt. Println ( value. Int ( ) + 13 )
iv := value. Interface ( )
num2 := iv. ( int )
fmt. Println ( num2)
}
func TestReflect ( t * testing. T) {
var num int = 100
reflectTest01 ( num)
}
结构体
func reflectTest01 ( stu Student) {
stuType := reflect. TypeOf ( stu)
fmt. Println ( "stuType" , stuType)
fmt. Println ( "stuType Kind" , stuType. Kind ( ) )
stuValue := reflect. ValueOf ( stu)
fmt. Println ( "stuValue" , stuValue)
fmt. Println ( "stuValue Kind" , stuValue. Kind ( ) )
stuIv := stuValue. Interface ( )
fmt. Printf ( "接口 类型 %T \n" , stuIv)
student, ok := stuIv. ( Student)
if ok {
fmt. Printf ( "接口 类型 %T \n" , student)
}
}
type Student struct {
Name string
Age int
}
func TestReflect ( t * testing. T) {
student := Student{
"tom" , 13 ,
}
reflectTest01 ( student)
}
注意
reflect.Value.Kind 获取变量的类别,返回的是一个产量 Type 是类型 Kind是类别,Type和Kind可能相同,可能不同 比如:int Type :int ; Kind:int Student Type:Student ; Kind:struct 通过反射可以在让变量在 interface{} 和 Reflect.Value 之间相互转换 使用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,否则panic 通过反射修改变量,注意当使用setXxx方法来设置需要通过对应的指针来完成,同时需要使用reflect.Value.Elem
func TestReflect ( t * testing. T) {
i := 10
iValue := reflect. ValueOf ( & i)
iValue. Elem ( ) . SetInt ( 20 )
fmt. Println ( i)
}
练习
func TestReflect ( t * testing. T) {
var v float64 = 1.2
value := reflect. ValueOf ( v)
vType := value. Type ( )
vKind := value. Kind ( )
fmt. Println ( vType, vKind, value)
fv, ok := value. Interface ( ) . ( float64 )
if ok {
fmt. Printf ( "FV 的值 %v 类型 %T \n" , fv, fv)
}
}
最佳实践
遍历结构体的方法,调用接头体的方法,获取结构体的标签
func TestReflect ( t * testing. T) {
m := Monster{
Name: "黄书狼" ,
Age: 400 ,
Score: 30.8 ,
}
mType := reflect. TypeOf ( m)
mValue := reflect. ValueOf ( m)
if mValue. Kind ( ) != reflect. Struct {
fmt. Println ( "expect struct" )
return
}
num := mValue. NumField ( )
fmt. Printf ( "struct has %d field \n" , num)
for i := 0 ; i < num; i++ {
fmt. Printf ( "字段 %d 值为%v\n" , i, mValue. Field ( i) )
tagVal := mType. Field ( i) . Tag. Get ( "json" )
if tagVal != "" {
fmt. Printf ( "字段 %d : tag为%v\n" , i, tagVal)
}
}
methodNum := mValue. NumMethod ( )
fmt. Printf ( "struct has %d method \n" , methodNum)
mValue. Method ( 1 ) . Call ( nil )
var params [ ] reflect. Value
params = append ( params, reflect. ValueOf ( 10 ) )
params = append ( params, reflect. ValueOf ( 40 ) )
res := mValue. Method ( 0 ) . Call ( params)
fmt. Println ( "res " , res[ 0 ] . Int ( ) )
}