Introduction of Golang reflection mechanism

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

Introduction of Golang reflection mechanism

The go language provides a mechanism for updating variables, viewing values at run time, invoking methods, and directly manipulating their layout, known as Reflection (reflection), without knowing the type at compile time.

Reflect. Type and reflect. Value

The reflection feature is provided by the reflect package, which defines two important types: type and value, respectively, representing the types and values of the variables. Inside the reflector package, the reflect is provided. TypeOf and reflect. ValueOf, returns the type and Value of the object being inspected:

func TypeOf(i interface{}) Typefunc ValueOf(i interface{}) Value

As you can see, the arguments for TypeOf and valueof are interface{} types, an implicit type conversion occurs when a specific value is assigned to a interface{} type, and the conversion generates an interface value that contains two partial content: The dynamic type part is the type of the operand, The dynamic value portion is the value of the operand.

Reflect. typeof returns the dynamic type of the interface value, paying attention to the type of the specific value returned, not the interface type. For example, the following output is "*os." File "instead of" IO. Writer ":

var w io.Writer = os.Stdoutfmt.Println(reflect.TypeOf(v)) // "*os.File"

In the same vein, reflect. valueof returns the interface dynamic value to reflect. The form of value is returned, with reflect. typeof similar to:

v := reflect.ValueOf(3)fmt.Println(v) //"3"

The type method that invokes value returns its types as Reflect.type:

t := v.Type() //an reflect.Typefmt.Println(t.String()) //"int"

Reflect. The inverse operation of the valueof is the Reflect.Value.Interface method, which returns a interface{} interface value, with reflect. Value contains the same specific value:

v := reflect.ValueOf(3)x := v.Interface()i := x.(int)fmt.Printf("%d\n", i) //"3"

Reflect. Both value and interface{} can contain arbitrary values. The difference between the two is that the Null interface (interface{}) hides the layout information of the value, the built-in operation, and the associated method, unless we know its dynamic type and penetrate it with a type assertion, otherwise we can do very little to the value contained. In contrast, value has a number of methods that can be used to parse the contained value without knowing its type.

Using reflection to traverse structure body

The previous article describes the types and structures that use reflection to print a simple data type, and then describes how to traverse a struct with reflection, and you can refer to one of the following code:

Func Display (i interface{}) {FMT. Printf ("Display%t\n", i) Display ("", reflect. ValueOf (i)}} Func display (path string, v reflect. Value) {switch v.kind () {case reflect. Int, reflect. Int8, reflect. Int16, reflect. Int32, reflect. Int64, reflect. Uint, reflect. Uint8, reflect. Uint16, reflect. Uint32, reflect. Uint64, reflect. Float32, reflect. Float64, reflect. Bool, reflect. String:fmt. Printf ("%s:%v (%s) \ n", Path, V, V.type (). Name ()) case reflect. Ptr:v = V.elem () display (path, v) case reflect. Slice, reflect. Array:for I: = 0; I < V.len (); i++ {display ("+path+" ["+strconv. Itoa (i) + "]", V.index (i))} case reflect. Struct:t: = V.type () for I: = 0; I < V.numfield (); i++ {display ("+path+". +t.field (i).       Name, V.field (i))}    }   } 

First, a display function is created, and then a display,display function is encapsulated within the function that recursively iterates through the fields inside the struct, and if it is a simple data type, it is printed directly, otherwise it iterates through struct members. Next, simply parse the display function:

array and tangent edges : If V is an array or tangent, then V is called. Len () function, gets the length of the array or tangent edge, and calls v. Index (i) to get the first element of the array or tangent edge.

pointer : If V is a pointer, V is called. Elem (), gets the variable that the pointer points to, and then recursively the variable.

struct : If V is a struct, V.numfield () returns the number of fields in the struct, and V.field (i) returns the I field.

Of course, the switch statement here, the type of V.kind () is not only this, but also some other types, such as reflect. Map,reflect. Interface, reflect. Func,reflect. Chan et cetera, the purpose of this code is simply to show how to use reflection to traverse the structure, so there is no need to consider all the structures, all of which are very similar.

Next we define a struct with an inline struct, and call the display function to traverse the struct:

type Person struct {    Name   string       Age    int      Gender bool    }type Student struct {    Person *Person      Course []string     Core   []float32    }func main() {    st := &Student{        Person: &Person{                Name:   "Jim",                      Age:    18,                     Gender: true,                   },          Course: []string{"Math", "Data Structe", "Algorithm"},              Core:   []float32{90.5, 85, 89.9},          }       Display(st) }

The output is as follows:

Display *main.Student  .Person.Name: Jim (string)     .Person.Age: 18 (int)    .Person.Gender: true (bool)    .Course[0]: Math (string)     .Course[1]: Data Structe (string)     .Course[2]: Algorithm (string)    .Core[0]: 90.5 (float32)     .Core[1]: 85 (float32)     .Core[2]: 89.9 (float32)

Use reflect. Value Modify values

In Golang, reflection is not only used to parse variable values, but also to change the values of variables, and then describes how to use reflect. Value to set the values of the variables.

What we need to know is that we pass the argument to reflect. When valueof gets Reflect.value, a copy of the parameter is passed in, so reflect.valueof gets the reflect.value of the copy of the incoming parameter, and the modification has no effect on the original data. So if we want to change the original value, we need to use the pointer, and then we need to use the Elem method to get the variable pointed to by the pointer, by modifying the variable returned by Elem (), we can really modify the value of the original variable, as follows:

x := 2v := reflect.ValueOf(&x)e := v.Elem()e.Set(reflect.ValueOf(3))fmt.Println(x) //"3"

Here, there are some basic types of set variants: Setint, Setuint, SetString, SetFloat, and so on:

e.SetInt(4)fmt.Println(e) //"4"

Before updating a variable, we can use the Canset method to determine if it can be changed, and if you change a reflect that cannot be changed. Value that will cause panic:

fmt.Println(e.CanSet()) //"true"d := reflect.ValueOf(2)fmt.Println(d.CanSet()) //"false"d.Set(reflect.ValueOf(4)) // 这里将导致panic

Note

Golang's reflection is a powerful tool for both functional and expressive abilities, but it is prudent to use it, specifically for the following reasons:

    • Reflection-based code is vulnerable. Each writing that causes the compiler to report type errors, there is a corresponding misuse of the notation in the reflection. The compiler will be able to report this error to you at compile time, and the reflection error will not be reported in a crash mode until execution. And reflection also reduces the security and accuracy of automatic refactoring and analysis tools because they cannot detect type information.

    • We want to avoid using reflection because reflection-related operations cannot do static type checking, so it is hard to understand the large number of code that uses reflection. For accepting interfacef{} or reflect. Function of value, be sure to write clearly the expected parameter types and other constraints

    • Reflection-based functions are one or two orders of magnitude slower than functions optimized for a particular type. Testing is good for reflection, but for functions on critical paths, it's best to avoid reflection.

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.