反射
包 reflect
反射可以在运行时动态获取变量/实例的各种信息,例如:变量的类型; 如果是结构体变量,反射还可以获取到结构体本身的信息(结构体的字段、方法等); 通过反射可以修改变量的值,可以调用关联的方法;
反射的相关函数
relect.TypeOf(变量名)
: 获取变量的类型,返回 reflect.Type
类型;relect.ValueOf(变量名)
: 获取变量的值,返回 reflect.Value
类型; reflect.Value
是一个结构体类型,通过 reflect.Value
可以获取到关于该变量的很多信息;reflect.Value
需要调用具体类型的方法, 获取转换类型后的值,例如:val.Int()
;具体类型使用断言判断;func (v Value) Interface() (i interface{})
: 此函数将 reflect.Value
转换成空接口;借助断言判断并转换成真实类型;
type Type
func TypeOf ( i interface { } ) Type
func PtrTo ( t Type) Type
func SliceOf ( t Type) Type
func MapOf ( key, elem Type) Type
func ChanOf ( dir ChanDir, t Type) Type
type Value
func ValueOf ( i interface { } ) Value
...
基本数据类型的反射
借助空接口 进行转换; 使用reflect.Value.Int()
转换成真实类型; 使用reflect.Value.Interface()
+ 断言,判断类型并转换成真实类型,进行后续操作;
反射设置变量值
需要传入地址; 使用Elem()
:reVal.Elem().SetInt(19)
;
结构体类型的反射
反射操作结构体的属性和方法
field := val.NumField();/val.Field(i)
, 输出:NumField 字段个数;Field类似于java 的字段数组;字段修改,传参时需要传入指针;此时操作Field 需要加 reflect.ValueOf().Elem().Field(0)
, Elem 相当于解地址; 字段修改使用:val.Elem().Field(0).SetString("xxx")/ SetInt(18)
, 字段也按结构体的定义先后排序; 方法调用:val.Method(2).Call(nil)
; val.MethodByName("Print").Call(nil)
; 方法首字母必须大写才有对应的反射的访问权限; 方法顺序 按照 ASCII 码的顺序排列,使用 val.Method(2).Call(nil)
时传入的2/索引值,需要用到; 调用带参数方法,入参要使用[]reflect.Value
+ append
构造切片;具体看示例代码;
反射获取变量的类别
reflect.Type.Kind()
reflect.Value.Kind()
:Kind:
type Kind uint
Kind代表Type类型值表示的具体分类。零值表示非法分类。
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)
示例代码
package main
import (
"fmt"
"reflect"
)
func baseTypeReflect ( i interface { } ) {
reType := reflect. TypeOf ( i)
fmt. Println ( "type(reflect.Type 类型)=" , reType)
val := reflect. ValueOf ( i)
fmt. Println ( "value(reflect.Value 类型)=" , val)
num2 := 10 + val. Int ( )
fmt. Println ( "num2=" , num2)
fmt. Println ( "==>> reflect.Value 转换成空接口,再借助断言转换+判断:" )
valIface := val. Interface ( )
valInt, ok := valIface. ( int )
if ok {
n2 := valInt + 1
fmt. Println ( "(valInt )=" , valInt)
fmt. Println ( "(valInt + 1)=" , n2)
} else {
fmt. Println ( "val 不是int类型..." )
}
}
type Student struct {
Name string
Age int
}
func structReflect ( i interface { } ) {
reType := reflect. TypeOf ( i)
fmt. Println ( "type(reflect.Type 类型)=" , reType)
fmt. Printf ( "type 的真实类型(go类型)=%T \n" , reType)
val := reflect. ValueOf ( i)
fmt. Println ( "value(reflect.Value 类型)=" , val)
fmt. Printf ( "value 的真实类型(go类型)=%T \n" , val)
fmt. Println ( "==>> reflect.Value 转换成空接口,再借助断言转换+判断:" )
valIface := val. Interface ( )
valStu, ok := valIface. ( Student)
if ok {
fmt. Println ( "(student )=" , valStu)
} else {
fmt. Println ( "val 不是student类型..." )
}
}
func kindReflect ( i interface { } ) {
reType := reflect. TypeOf ( i)
val := reflect. ValueOf ( i)
kind := reType. Kind ( )
fmt. Println ( "reflect.TypeOf(i).kind=" , kind)
valKind := val. Kind ( )
fmt. Println ( "reflect.ValueOf(i).kind=" , valKind)
valIface := val. Interface ( )
valStu, ok := valIface. ( Student)
if ok {
fmt. Printf ( "入参的类型是:%T \n" , valStu)
} else {
fmt. Println ( "val 不是student类型..." )
}
}
func altVar ( i interface { } ) {
reVal := reflect. ValueOf ( i)
reVal. Elem ( ) . SetInt ( 18 )
}
func ( s Student) Print ( ) {
fmt. Println ( "call_func: Print()" )
fmt. Println ( "学生的名字是:" , s. Name)
}
func ( s Student) GetSum ( n1, n2 int ) int {
return n1 + n2
}
func ( s Student) Set ( name string , age int ) {
s. Name = name
s. Age = age
}
func getStructField ( i interface { } ) {
val := reflect. ValueOf ( i)
fmt. Println ( "val=" , val)
field := val. NumField ( )
fmt. Println ( "NumField=" , field)
for i := 0 ; i < field; i++ {
fmt. Printf ( "第 %d 个字段的值是: %v \n" , i, val. Field ( i) )
}
}
func callStructMethod ( i interface { } ) {
val := reflect. ValueOf ( i)
fmt. Println ( "val=" , val)
numMethod := val. NumMethod ( )
fmt. Println ( "numMethod=" , numMethod)
fmt. Println ( "val.Method(1)=" , val. MethodByName ( "Print" ) )
val. MethodByName ( "Print" ) . Call ( nil )
val. Method ( 1 ) . Call ( nil )
fmt. Println ( "==>> 调用带参数的 GetSum 方法:" )
var params [ ] reflect. Value
params = append ( params, reflect. ValueOf ( 1 ) )
params = append ( params, reflect. ValueOf ( 2 ) )
sum := val. Method ( 0 ) . Call ( params)
fmt. Println ( "sum=" , sum[ 0 ] )
}
func altStructField ( i interface { } ) {
val := reflect. ValueOf ( i)
fmt. Println ( "val=" , val)
field := val. Elem ( ) . NumField ( )
fmt. Println ( "NumField=" , field)
for i := 0 ; i < field; i++ {
fmt. Printf ( "第 %d 个字段的值是: %v \n" , i, val. Elem ( ) . Field ( i) )
}
fmt. Println ( "==>> 修改结构体的字段值:(脑斧 ->小脑斧 -> 小脑斧~)" )
val. Elem ( ) . Field ( 0 ) . SetString ( "小脑斧" )
val. Elem ( ) . FieldByName ( "Name" ) . SetString ( "小脑斧~" )
}
func main ( ) {
fmt. Println ( "==>> 反射:基本数据类型:" )
var num int = 10
baseTypeReflect ( num)
fmt. Println ( "\n==>> 反射:对结构体进行反射:" )
student := Student{ Name: "脑斧" , Age: 18 }
structReflect ( student)
fmt. Println ( "\n==>> 反射获取变量类别(kind):" )
kindReflect ( student)
kindReflect ( & num)
kindReflect ( num)
fmt. Println ( "\n==>> 反射设置变量值:" )
fmt. Println ( "num 反射修改前值为:" , num)
altVar ( & num)
fmt. Println ( "num 利用反射修改后值为:" , num)
fmt. Println ( "\n==>> 反射操作结构体的属性和方法:" )
fmt. Println ( "==>> 反射查询结构体的属性:" )
getStructField ( student)
fmt. Println ( "==>> 反射调用结构体的方法:" )
callStructMethod ( student)
fmt. Println ( "\n==>> 反射修改结构体字段的值:" )
altStructField ( & student)
fmt. Println ( "student=" , student)
}
运行结果
== >> 反射:基本数据类型:
type( reflect.Type 类型) = int
value( reflect.Value 类型) = 10
num2 = 20
== >> reflect.Value 转换成空接口,再借助断言转换+判断:
( valInt ) = 10
( valInt + 1 ) = 11
== >> 反射:对结构体进行反射:
type( reflect.Type 类型) = main.Student
type 的真实类型( go类型) = *reflect.rtype
value( reflect.Value 类型) = { 脑斧 18 }
value 的真实类型( go类型) = reflect.Value
== >> reflect.Value 转换成空接口,再借助断言转换+判断:
( student ) = { 脑斧 18 }
== >> 反射获取变量类别( kind) :
reflect.TypeOf( i) .kind= struct
reflect.ValueOf( i) .kind= struct
入参的类型是:main.Student
reflect.TypeOf( i) .kind= ptr
reflect.ValueOf( i) .kind= ptr
val 不是student类型.. .
reflect.TypeOf( i) .kind= int
reflect.ValueOf( i) .kind= int
val 不是student类型.. .
== >> 反射设置变量值:
num 反射修改前值为: 10
num 利用反射修改后值为: 18
== >> 反射操作结构体的属性和方法:
== >> 反射查询结构体的属性:
val = { 脑斧 18 }
NumField = 2
第 0 个字段的值是: 脑斧
第 1 个字段的值是: 18
== >> 反射调用结构体的方法:
val = { 脑斧 18 }
numMethod = 3
val.Method( 1 ) = 0x649020
call_func: Print( )
学生的名字是: 脑斧
call_func: Print( )
学生的名字是: 脑斧
== >> 调用带参数的 GetSum 方法:
sum = 3
== >> 反射修改结构体字段的值:
val = & { 脑斧 18 }
NumField = 2
第 0 个字段的值是: 脑斧
第 1 个字段的值是: 18
== >> 修改结构体的字段值:( 脑斧 -> 小脑斧 -> 小脑斧~)
student = { 小脑斧~ 18 }