golang Reflect包

Reflect包

Reflect 反射包有2个重要的类型,分别经过Typeof()ValueOf()返回。 分别在源码包里的reflect包中的type.govalue.goapp

Type

TypeOf() 返回一个Type接口类型,源码中ui

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。能够调用他的方法code

例如:对象

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。get

Value

ValueOf() 返回一个Value结构体类型,源码中源码

type Value struct {
	typ *rtype
	ptr unsafe.Pointer
	flag
}

rtypeKind()不一样的是,其中flag 是一个uintptr类型,实现了kind()方法。新增了类型,源码中string

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{}或利用Indirect()方法来判断。,若须要赋值则须要传入对象的指针,也就是值传递或址传递的意思。 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++{
		argType:= reflect.Indirect(v.Field(i))
		if argType.Kind()==reflect.Struct {
                    fmt.Println("================>")
		    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()返回方法的基本属性,但并本身没有现实调用方法,而是经过调用ValueOfCall(),而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方法
相关文章
相关标签/搜索