Reflect 反射包有2個重要的類型,分別經過Typeof()
和ValueOf()
返回。 分別在源碼包裏的reflect
包中的type.go
和value.go
app
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
ValueOf() 返回一個Value
結構體類型,源碼中源碼
type Value struct { typ *rtype ptr unsafe.Pointer flag }
與rtype
的Kind()
不一樣的是,其中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()
返回方法的基本屬性,但並本身沒有現實調用方法,而是經過調用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方法