golang Reflect包
2019獨角獸企業重金招聘Python工程師標準>>>
Reflect包
Reflect 反射包有2個重要的類型,分別通過Typeof()和ValueOf()返回。 分別在源碼包里的reflect包中的type.go和value.go
Type
TypeOf() 返回一個Type接口類型,源碼中
type Type interface {Align() intFieldAlign() intMethod(int) MethodMethodByName(string) (Method, bool)NumMethod() intName() stringPkgPath() stringSize() uintptrString() stringKind() KindImplements(u Type) boolConvertibleTo(u Type) boolComparable() boolBits() intChanDir() ChanDirIsVariadic() boolElem() TypeField(i int) StructFieldFieldByIndex(index []int) StructFieldFieldByName(name string) (StructField, bool)FieldByNameFunc(match func(string) bool) (StructField, bool)In(i int) TypeKey() TypeLen() intNumField() intNumIn() intNumOut() intOut(i int) Typecommon() *rtypeuncommon() *uncommonType }有一個rtype結構體 實現了Type接口的所有方法。源碼:
type rtype struct {size uintptrptrdata 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()) //stringargTest1 :=&testStruct{} v1 :=reflect.TypeOf(argTest1)fmt.Println(v1.Kind()) // ptrargTest1 :=&testStruct{} v1 :=reflect.TypeOf(*argTest1)fmt.Println(v1.Kind()) //structargTest1 :=&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.Typeif 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 *rtypeptr unsafe.Pointerflag }與rtype的Kind()不同的是,其中flag 是一個uintptr類型,實現了kind()方法。新增了類型,源碼中
const (flagKindWidth = 5 // there are 27 kindsflagKindMask flag = 1<<flagKindWidth - 1flagStickyRO flag = 1 << 5flagEmbedRO flag = 1 << 6flagIndir flag = 1 << 7flagAddr flag = 1 << 8flagMethod flag = 1 << 9flagMethodShift = 10flagRO 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()) // truev1.Elem().Index(0).SetInt(10) fmt.Println(arr) // 10,2,3,4Elem()方法只區分了interface{} ptr,再處理指針類型的時候需先調用Elem()方法得到一個具體的基礎類型。可以利用Kind()方法來得知ValueOf返回的是指針還是interfaec{}或利用Indirect()方法來判斷。,若需要賦值則需要傳入對象的指針,也就是值傳遞或址傳遞的意思。 struct的取值,賦值只是調用了不同方法。例如:
type student struct{numb intname stringAge intclass *class } type class struct{classNumber intclassName 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 intfunc (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方法轉載于:https://my.oschina.net/johnhjwsosd/blog/1629882
總結
以上是生活随笔為你收集整理的golang Reflect包的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 支持向量机中的函数距离的理解
- 下一篇: laravel模型中设计使用单选按钮的方