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方法
相關文章
相關標籤/搜索