Go Reflex and Interface supplements

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

The basis for the dynamic and reflective interface of Go is that the compile time provides the type information for the runtime. There are two structures at the bottom of the interface, and the previous section describes the Iface with the method, which complements the eface structure without methods.

The Eface of interface

Any object in go can be represented as interface{}. It plays the same role as the void* in C, the difference is that interface{} contains type information, which enables reflection.

EFACE Data Structure Description : The gcdata domain is used for garbage collection, size describes the size of the type, hash represents the hash value of the data, is aligned, align is the alignment of fieldalign the data embedded in the structure, kind is the enumeration value. algis an array of function pointers, which stores hash/equal/print/copy four function operations. A uncommentType set of methods that point to this type.

type eface struct {_type *_typedata unsafe.Pointer}type _type struct {size       uintptrptrdata    uintptr // size of memory prefix holding all pointershash       uint32_unused    uint8align      uint8fieldalign uint8kind       uint8alg        *typeAlggcdata  *byte_string *stringx       *uncommontypeptrto   *_typezero    *byte // ptr to the zero value for this type}

Run-time convt2e

the T2E conversion is assigned to null interface{}, and the runtime calls the Conv class function convT2E . convT2IAs with, there is a memory copy of the type conversion to interface var i interface{} = u . See Iface.go source code when found that convI2I the interface conversion is not allocated memory and copy data, the reason may be the data domain inside the Go interface, is not open way for external modification, so the conversion between interfaces can use the same block of memory.

func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e interface{}) {ep := (*eface)(unsafe.Pointer(&e))  ...if x == nil {x = newobject(t)}typedmemmove(t, x, elem)ep._type = tep.data = x}return}

In the following example, modifying U does not affect the memory data of I interface, because I copy the U by CONVT2E when the value is assigned. This is also the reason why the variable data cannot be changed directly when the non-pointer variable is reflected , because the reflection will first turn the variable into the interface type and get a copy of the variable.

u := User{1, "Tom"}var i interface{} = uu.id = 2u.name = "Jack"// u {2, "Jack"}// i.(User) {1, "Tom"}

Nil's understanding

Uninitialized interface types, pointers, functions, slice,cannel, and maps are nil. for interface is special, only eface type and data are nil, or Iface's type and data are nil, interface{} is nil.

type Duck interface{    Walk()}var i interface{}   // nilvar d Duck   // nilvar v *T   // nili = v   // (*T)(nil) not nil

Type assertion

Strictly speaking, go does not support generic programming, but through the interface can be implemented generic programming, the following reflect analysis of a reflect implementation of the generic example. Interface like other types of conversions generally require assertions. Here are just a few examples of eface, but it is also possible to determine whether a type implements an interface by asserting it.

func do(v interface{}) {n, ok := v.(int)if !ok {...}}func doswitch(i interface{}) {switch v := i.(type) {case int: ...}}

The corresponding go source in the iface.go. The assertE2T procedure determines whether the Type field of the Eface is equal to the target type, and also copies the data if it is equal. assertI2Talso copy the data, but he compares the iface.tab._type to the target type.

func assertE2T(t *_type, e interface{}, r unsafe.Pointer) {ep := (*eface)(unsafe.Pointer(&e))if ep._type == nil {panic(&TypeAssertionError{"", "", *t._string, ""})}if ep._type != t {panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""})}if r != nil {if isDirectIface(t) {writebarrierptr((*uintptr)(r), uintptr(ep.data))} else {typedmemmove(t, r, ep.data)}}}

Reflect analysis

The reflection mechanism provides a mechanism for examining the [type value] pairs stored in an interface variable. According to the reflection of laws of Reflectiongo can summarize three points, that is, reflection can get reflect object from interface, while the Interface() reflect object can be restored by means of a interface, if you want to modify the reflection object, The object must be settable .

typeof and ValueOf implementation

Gets the implementation of the reflected object, based on the operation of the interface underlying data. The object first passes through convT2E , and then emptyinterface directly points to the Type field of the Eface. typeOfthe returned type is an interface that implements a number of operations on type _type. valueOfreturn is the Value struct, which contains data fields and type field information.

func TypeOf(i interface{}) Type {eface := *(*emptyInterface)(unsafe.Pointer(&i))return toType(eface.typ)}func ValueOf(i interface{}) Value {if i == nil {return Value{}}escapes(i)return unpackEface(i)}func unpackEface(i interface{}) Value {e := (*emptyInterface)(unsafe.Pointer(&i))t := e.typif t == nil {return Value{}}f := flag(t.Kind())if ifaceIndir(t) {f |= flagIndir}return Value{t, unsafe.Pointer(e.word), f}}
type Type interface{  ...Method(int) MethodMethodByName(string) (Method, bool)NumMethod() intNumField()Field(i) StructFieldFieldByName(name string) (StructField, bool)  ...}type Value struct {typ *rtypeptr unsafe.Pointerflag}

Get the struct field information by type

You can get the struct information for a type instance by reflect, such as the name type or label for each field.

// A StructField describes a single field in a struct.type StructField struct {Name string  // Name is the field name.PkgPath stringType      Type      // field typeTag       StructTag // field tag stringOffset    uintptr   // offset within struct, in bytesIndex     []int     // index sequence for Type.FieldByIndexAnonymous bool      // is an embedded field}type Person struct {Name string `json:"name"`Age  int    `json:"age"`}func main() {nino := Person{"nino", 27}t := reflect.TypeOf(nino)n := t.NumField()for i := 0; i < n; i++ {fmt.Println(t.Field(i).Name, t.Field(i).Type, t.Field(i).Tag)}}// Name string json:"name"// Age int json:"age"

Implementing generics with value

In order to solve the method accepting different types of slice as arguments, it can be done with reflection. For the types that can be remembered for length and random access, you can pass v.Len() and v.Index(i) get their first few elements.

V.index (i). Interface () will reflect. Value is reflected back to the interface type

func method(in interface{}) (ok bool) {v := reflect.ValueOf(in)if v.Kind() == reflect.Slice {ok = true} else {return false}num := v.Len()for i := 0; i < num; i++ {fmt.Println(v.Index(i).Interface())}return ok}func main() {s := []int{1, 3, 5, 7, 9}b := []float64{1.2, 3.4, 5.6, 7.8}method(s)method(b)}

Modifying reflect object values through Elem

Understanding of the 3rd lawsofreflect reflect.ValueOf If you pass in X directly, V is the reflect object of a copy of X. Modifying the value of V does not work on X. P is the reflect object that points to the X pointer, and modifying the value of P is the point of modifying the pointer, which also does not work on X, so it is also cannotset . The p.Elem() original data can be modified only by the equivalent of acquiring the *p reflect object v.SetFloat(7.2) .

var x float64 = 3.4v := reflect.ValueOf(x)   // can not setp := reflect.ValueOf(&x)  // can not sete := p.Elem()  // can set
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.