go語言中的反射的使用

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

今天嘗試了一下使用go語言中的反射來將struct類型轉換成xml,結果相當糾結。首先去看了一下go的reflect包的實現,根據go的規則,首先應該去看一個NewXXX的方法,結果發現了一個叫NewValue的方法,通過這個方法我們能夠得到一個Value介面。另外我們還應該注意到,go的反映實現中將Type和Value分開了,於是還有另外一個介面Type.

  type Value interface {    // Type returns the value's type.    Type() Type    // Interface returns the value as an interface{}.    Interface() interface{}    // CanSet returns whether the value can be changed.    // Values obtained by the use of non-exported struct fields    // can be used in Get but not Set.    // If CanSet() returns false, calling the type-specific Set    // will cause a crash.    CanSet() bool    // SetValue assigns v to the value; v must have the same type as the value.    SetValue(v Value)    // Addr returns a pointer to the underlying data.    // It is for advanced clients that also    // import the "unsafe" package.    Addr() uintptr    // Method returns a FuncValue corresponding to the value's i'th method.    // The arguments to a Call on the returned FuncValue    // should not include a receiver; the FuncValue will use    // the value as the receiver.    Method(i int) *FuncValue    // contains unexported methods}type Type interface {    // PkgPath returns the type's package path.    // The package path is a full package import path like "container/vector".    // PkgPath returns an empty string for unnamed types.    PkgPath() string    // Name returns the type's name within its package.    // Name returns an empty string for unnamed types.    Name() string    // String returns a string representation of the type.    // The string representation may use shortened package names    // (e.g., vector instead of "container/vector") and is not    // guaranteed to be unique among types.  To test for equality,    // compare the Types directly.    String() string    // Size returns the number of bytes needed to store    // a value of the given type; it is analogous to unsafe.Sizeof.    Size() uintptr    // Bits returns the size of the type in bits.    // It is intended for use with numeric types and may overflow    // when used for composite types.    Bits() int    // Align returns the alignment of a value of this type    // when allocated in memory.    Align() int    // FieldAlign returns the alignment of a value of this type    // when used as a field in a struct.    FieldAlign() int    // Kind returns the specific kind of this type.    Kind() Kind    // For non-interface types, Method returns the i'th method with receiver T.    // For interface types, Method returns the i'th method in the interface.    // NumMethod returns the number of such methods.    Method(int) Method    NumMethod() int    // contains unexported methods}

然後包裡還根據每種資料類型都定義了相應的XXXType和XXXValue結構體,那麼我們如何得到這些結構體的執行個體呢?因為只有得到這些構體的執行個體才能利用反映來操縱這些資料。於是很醜陋的地方來了,你需要使用.(type)來得到當前這個變數的類型,而這個使用必須在switch中,請看下面的例子

func test(data interface{}) {    switch rvalue := reflect.NewValue(data).(type) {    default:        println(reflect.Typeof(rvalue).String())    }       switch rtype := reflect.Typeof(data).(type) {    default:        println(reflect.Typeof(rtype).String())    }       switch rvalue := data.(type) {    default:        println(reflect.Typeof(rvalue).String())    }   }

NewValue建立了一個data的Value介面,但是這個介面是誰實現的呢?通過.(type)就可以得到。

Typeof建立了一個data的Type介面,同樣的這個介面也可以通過.(type)得到它的實現。

而如果不使用reflect裡的任何方法直接對變數data使用.(type),那麼就會得到這個介面的實現。

因此從這裡我們可以看到go語言中使用反映需要兩個條件,一個是通過type得到它的實現變數,一個是通過reflect裡提供的介面來進行操作。


但是很噁心的是,每次操作都必須通過switch case來執行,比如最後My Code就變成了如下這個樣子:

func asString(val interface{}) string {switch value := reflect.NewValue(val).(type) {case *reflect.StringValue:return value.Get()case *reflect.BoolValue:return strconv.Btoa(value.Get())case *reflect.IntValue:return strconv.Itoa64(value.Get())default:panic("invalid type for xml generator")}return ""}func toXml(val interface{}, writer io.Writer) {switch value := reflect.NewValue(val).(type) {case *reflect.StructValue:writer.Write([]byte("<"))writer.Write([]byte(reflect.Typeof(val).Name()))switch vtype := reflect.NewValue(val).Type().(type) {case *reflect.StructType://compose attributefor i := 0; i < value.NumField(); i++ {field := vtype.Field(i)if field.Tag != "attr" {continue}writer.Write([]byte(" "))writer.Write([]byte(field.Name))writer.Write([]byte("=/""))writer.Write([]byte(asString(value.Field(i).Interface())))writer.Write([]byte("/""))}writer.Write([]byte(">"))//compose childrenfor i := 0; i < value.NumField(); i++ {field := vtype.Field(i)if field.Tag == "attr" {continue}switch child := value.Field(i).(type) {case *reflect.StructValue:toXml(child.Interface(), writer)case *reflect.ArrayValue:case *reflect.SliceValue:writer.Write([]byte("<"))writer.Write([]byte(field.Name))writer.Write([]byte(">"))for i := 0; i < child.Len(); i++ {switch elem := child.Elem(i).(type) {case *reflect.StructValue:toXml(elem.Interface(), writer)default:panic("invalid type for array, only struct supported")}}writer.Write([]byte(""))default:writer.Write([]byte(asString(child.Interface())))}}//compose endwriter.Write([]byte(""))default:panic("invalid type: only array, slice, struct and primitive type supported")}default:panic("invalid type, only struct supported")}}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.