golang Reflect包
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
Reflect包
Reflect 反射包有2個(gè)重要的類型,分別通過(guò)Typeof()和ValueOf()返回。 分別在源碼包里的reflect包中的type.go和value.go
Type
TypeOf() 返回一個(gè)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 }有一個(gè)rtype結(jié)構(gòu)體 實(shí)現(xiàn)了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會(huì)返回一個(gè)rtype。可以調(diào)用他的方法
例如:
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()方法來(lái)獲取反射對(duì)象的類型,如果是struct類型傳入的是一個(gè)地址,會(huì)得到ptr類型,可以傳入指向地址的值或者利用Elem()方法可以得到對(duì)應(yīng)的類型。所有基礎(chǔ)類型的基本屬性都可以通過(guò)rtype來(lái)獲得。基礎(chǔ)類型可以查看type.goKind類型中的包含。
獲取結(jié)構(gòu)體中所有元素的屬性。
func getStructArgProperty(t interface{}){var v reflect.Typeif reflect.TypeOf(t).Kind() == reflect.Ptr { //if reflect.TypeOf(t).Elem().Kind() != reflect.Struct{fmt.Println("不是結(jié)構(gòu)體")return}v =reflect.TypeOf(t).Elem()}else{if reflect.TypeOf(t).Kind() != reflect.Struct{fmt.Println("不是結(jié)構(gòu)體")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())}}} }但若要取到對(duì)象的值,則需要用到ValueOf。
Value
ValueOf() 返回一個(gè)Value結(jié)構(gòu)體類型,源碼中
type Value struct {typ *rtypeptr unsafe.Pointerflag }與rtype的Kind()不同的是,其中flag 是一個(gè)uintptr類型,實(shí)現(xiàn)了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()方法只區(qū)分了interface{} ptr,再處理指針類型的時(shí)候需先調(diào)用Elem()方法得到一個(gè)具體的基礎(chǔ)類型。可以利用Kind()方法來(lái)得知ValueOf返回的是指針還是interfaec{}或利用Indirect()方法來(lái)判斷。,若需要賦值則需要傳入對(duì)象的指針,也就是值傳遞或址傳遞的意思。 struct的取值,賦值只是調(diào)用了不同方法。例如:
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())}} }在需要修改的字段結(jié)構(gòu)體的屬性應(yīng)該為公開。
類型的方法
若要獲取類型的方法,使用TypeOf(),ValueOf()2中類型都可以獲取。
不同的是TypeOf()返回方法的基本屬性,但并自己沒(méi)有現(xiàn)實(shí)調(diào)用方法,而是通過(guò)調(diào)用ValueOf的Call(),而ValueOf則沒(méi)有返回方法的名字等基本屬性
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)) //方法名等結(jié)果,根據(jù)首字母排序 }for i:=0;i<v.NumMethod();i++{fmt.Println(v.Method(i)) //reflect方法對(duì)象。 }var para []reflect.Value para = append(para,reflect.ValueOf(11)) fmt.Println(v.Method(2).Call(para)) //調(diào)用Set方法para = append(para,reflect.ValueOf(&s)) fmt.Println(v1.Method(0).Func.Call(para[1:])) //調(diào)用Get方法轉(zhuǎn)載于:https://my.oschina.net/johnhjwsosd/blog/1629882
總結(jié)
以上是生活随笔為你收集整理的golang Reflect包的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 支持向量机中的函数距离的理解
- 下一篇: laravel模型中设计使用单选按钮的方