Reflect包
Reflect 反射包有2个重要的类型,分别通过Typeof()
和ValueOf()
返回。
分别在源码包里的reflect
包中的type.go
和value.go
Type
TypeOf() 返回一个Type
接口类型,源码中
type Type interface {
Align() int
FieldAlign() int
Method(int) Method
MethodByName(string) (Method, bool)
NumMethod() int
Name() string
PkgPath() string
Size() uintptr
String() string
Kind() Kind
Implements(u Type) bool
ConvertibleTo(u Type) bool
Comparable() bool
Bits() int
ChanDir() ChanDir
IsVariadic() bool
Elem() Type
Field(i int) StructField
FieldByIndex(index []int) StructField
FieldByName(name string) (StructField, bool)
FieldByNameFunc(match func(string) bool) (StructField, bool)
In(i int) Type
Key() Type
Len() int
NumField() int
NumIn() int
NumOut() int
Out(i int) Type
common() *rtype
uncommon() *uncommonType
}
有一个rtype
结构体 实现了Type
接口的所有方法。源码:
type rtype struct {
size uintptr
ptrdata uintptr
hash uint32
tflag tflag
align uint8
fieldAlign uint8
kind uint8
alg *typeAlg
gcdata *byte
str nameOff
ptrToThis typeOff
}
TypeOf会返回一个rtype。可以调用他的方法
例如:
argTest := "test"
v :=reflect.TypeOf(argTest)
fmt.Println(v.Kind()) //string
argTest1 :=&testStruct{}
v1 :=reflect.TypeOf(argTest1)
fmt.Println(v1.Kind()) // ptr
argTest1 :=&testStruct{}
v1 :=reflect.TypeOf(*argTest1)
fmt.Println(v1.Kind()) //struct
argTest1 :=&testStruct{}
v1 :=reflect.TypeOf(argTest1).Elem()
fmt.Println(v1.Kind()) // struct
可以利用Kind()
方法来获取反射对象的类型,如果是struct
类型传入的是一个地址,会得到ptr
类型,可以传入指向地址的值或者利用Elem()
方法可以得到对应的类型。所有基础类型的基本属性都可以通过rtype
来获得。基础类型可以查看type.goKind
类型中的包含。
获取结构体中所有元素的属性。
func getStructArgProperty(t interface{}){
var v reflect.Type
if reflect.TypeOf(t).Kind() == reflect.Ptr {
if reflect.TypeOf(t).Elem().Kind() != reflect.Struct{
fmt.Println("不是结构体")
return
}
v =reflect.TypeOf(t).Elem()
}else{
if reflect.TypeOf(t).Kind() != reflect.Struct{
fmt.Println("不是结构体")
return
}
v=reflect.TypeOf(t)
}
run(v)
}
func run(v reflect.Type){
for i:=0;i<v.NumField();i++{
argType:= v.Field(i)
if argType.Type.Kind() ==reflect.Ptr {
fmt.Println(argType.Name,argType.Type.Elem().Kind())
}else {
if argType.Type.Kind() ==reflect.Struct {
fmt.Println(" =====>",argType.Name)
run(argType.Type)
}else {
fmt.Println(argType.Name, argType.Type.Kind())
}
}
}
}
但若要取到对象的值,则需要用到ValueOf。
Value
ValueOf() 返回一个Value
结构体类型,源码中
type Value struct {
typ *rtype
ptr unsafe.Pointer
flag
}
与rtype
的Kind()
不同的是,其中flag 是一个uintptr
类型,实现了kind()
方法。新增了类型,源码中
const (
flagKindWidth = 5 // there are 27 kinds
flagKindMask flag = 1<<flagKindWidth - 1
flagStickyRO flag = 1 << 5
flagEmbedRO flag = 1 << 6
flagIndir flag = 1 << 7
flagAddr flag = 1 << 8
flagMethod flag = 1 << 9
flagMethodShift = 10
flagRO flag = flagStickyRO | flagEmbedRO
)
利用 ValueOf
取值,赋值
arr := [...]int{1,2,3,4}
v := reflect.ValueOf(arr)
fmt.Println(v) //[1,2,3,4]
v1 := reflect.ValueOf(&arr)
fmt.Println(v1) //&[1,2,3,4]
fmt.Println(v.Elem().CanSet()) // panic
fmt.Println(v1.Elem().CanSet()) // true
v1.Elem().Index(0).SetInt(10)
fmt.Println(arr) // 10,2,3,4
Elem()
方法只区分了interface{}
ptr
,再处理指针类型的时候需先调用Elem()
方法得到一个具体的基础类型。可以利用Kind()
方法来得知ValueOf
返回的是指针还是interfaec{}
,若需要赋值则需要传入对象的指针,也就是值传递或址传递的意思。
struct
的取值,赋值只是调用了不同方法。例如:
type student struct{
numb int
name string
Age int
class *class
}
type class struct{
classNumber int
className string
}
func structValueOf(){
s := student{numb:1,name:"john",Age:18,class:&class{classNumber:1}}
v := reflect.ValueOf(&s)
getStructArgProperty(v)
}
func getStructArgProperty(v reflect.Value){
for i:=0;i<v.NumField();i++{ //NumField()会判断Kind()是否为struct 不是的话会panic
argType:= v.Field(i)
if argType.Kind() == reflect.Ptr{
if argType.Elem().Kind() == reflect.Struct{
fmt.Println("========>")
getStructArgProperty(argType.Elem())
}else {
fmt.Println(argType.Elem().Kind()," : ",argType ," ",argType.Elem().CanSet())
}
}else {
if argType.Kind()==reflect.Struct {
getStructArgProperty(argType)
}else {
if argType.CanSet() == true && argType.Kind() == reflect.Int {
argType.SetInt(10)
}
fmt.Println(argType.Kind(), " : ", argType, " ", argType.CanSet())
}
}
}
}
在需要修改的字段结构体的属性应该为公开。
类型的方法
若要获取类型的方法,使用TypeOf()
,ValueOf()
2中类型都可以获取。
不同的是TypeOf()
返回方法的基本属性,但并自己没有现实调用方法,而是通过调用ValueOf
的Call()
,而ValueOf
则没有返回方法的名字等基本属性
type myType int
func (my *myType) Hi(){
fmt.Println("my value ",*my)
}
func (my *myType) Set(x int){
*my = myType(x)
}
func (my myType) Get() int{
fmt.Println("my value ", my)
return int(my)
}
var s myType = 1
v := reflect.ValueOf(&s)
v1 := reflect.TypeOf(s)
fmt.Println(" v ",v.NumMethod()) //3
fmt.Println(" v1 ",v1.NumMethod()) //1 传入的如果是值类型,则只返回值类型方法
for i:=0;i<v1.NumMethod();i++{
fmt.Println(v1.Method(i)) //方法名等结果,根据首字母排序
}
for i:=0;i<v.NumMethod();i++{
fmt.Println(v.Method(i)) //reflect方法对象。
}
var para []reflect.Value
para = append(para,reflect.ValueOf(11))
fmt.Println(v.Method(2).Call(para)) //调用Set方法
para = append(para,reflect.ValueOf(&s))
fmt.Println(v1.Method(0).Func.Call(para[1:])) //调用Get方法
有疑问加站长微信联系(非本文作者)