golang Reflect包

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

Reflect包

Reflect 反射包有2個重要的類型,分別通過Typeof()ValueOf()返回。分別在源碼包裡的reflect包中的type.govalue.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}

rtypeKind()不同的是,其中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())    // panicfmt.Println(v1.Elem().CanSet())   // truev1.Elem().Index(0).SetInt(10)fmt.Println(arr)  // 10,2,3,4

Elem()方法只區分了interface{} ptr,再處理指標類型的時候需先調用Elem()方法得到一個具體的基礎類型。可以利用Kind()方法來得知ValueOf返回的是指標還是interfaec{},若需要賦值則需要傳入對象的指標,也就是值傳遞或址傳遞的意思。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++{          //NumField()會判斷Kind()是否為struct 不是的話會panicargType:= v.Field(i)if argType.Kind() == reflect.Ptr{if argType.Elem().Kind() == reflect.Struct{fmt.Println("========>")getStructArgProperty(argType.Elem())}else {fmt.Println(argType.Elem().Kind(),"     : ",argType ,"   ",argType.Elem().CanSet())}}else {if argType.Kind()==reflect.Struct {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 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 = 1v := reflect.ValueOf(&s)v1 := reflect.TypeOf(s)fmt.Println(" v  ",v.NumMethod())   //3fmt.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.Valuepara = 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方法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.