This is a creation in Article, where the information may have evolved or changed.
This article is my reflection on the go language and the use of the memorandum, recorded the key relevant knowledge points, for the search. If there are errors in the text, please point out, so as not to mislead! Refer to this article please also specify the source: Go Language Memo: Reflection of the principle and use of detailed, thank you! Reference book "Go Language Bible", "Go Language Combat", "Go language study notes" and so on
Directory:
- Pre-knowledge
- Reflect. Typeof, reflect. ValueOf
- Value, Type
- Dynamic invocation
- The original object can be modified by reflection
- Implement features like "generics"
1. Preliminary knowledge:
- Go is a static type (the type specified at the time of Declaration), and it also has the underlying type (the underlying type specified when the type is defined, i.e., what form it is stored in);
- An interface variable stores a pair (value, type): Assigns a value to the specific value of the interface variable, and the type descriptor of the value, the kind;
- The interface variables of Go are statically typed: an interface type variable always maintains the same static type (that is, the interface type specified at the time of Declaration), and the values always satisfy this interface even if the type of the value it holds at run time changes.
- The static type of the interface determines which methods can be invoked with the interface variable (the method defined in the interface, which is a subset of the set of methods that hold the value);
- Reflection is a mechanism for examining (value, type) pairs stored in an interface variable, all of the information required by the reflection operation is derived from the interface variable (by converting the variable to an empty interface variable, thereby obtaining the value, type of the variable, so that a series of "reflection operations" can be performed);
- The two types in the reflect package: type and value, which provide access to the (value, type) pairs contained in an interface variable;
2. Reflection is supported by a reflect package, the Main method:
- Func TypeOf (i interface{}) Type:
such as reflect. Typeof (x), parameter x is saved as an interface value and passed as a parameter (copy), and the method internally restores the value of the interface to the type information of x to save as reflect. Type and returns;
- func ValueOf ( i interface{}) Value:
such as reflect. ValueOf (x), the formal parameter is saved as an interface value and passed as a parameter (copy), and the value of the interface value is restored internally to save as reflect. Value and return;
two main types of 3.reflect packages value, type : Both types provide a number of methods that allow us to examine and manipulate both types of
- Type interface: Can represent a go type
- Kind () Returns a constant that represents the underlying type of the specific type
- The Elem () method returns the base type of a pointer, array, slice, map, channel;
- Can be used to extract the struct tag, but also to automatically decompose, often in ORM mapping, data validation, etc.;
- Auxiliary judgment Methods implements (), Convertibleto (), Assignableto ()
- Value struct: Can hold values of any type
- The type () of the call to Value returns the reflect corresponding to the specific type. Type (static type)
- The Kind () call to Value returns a constant that represents the underlying type of the concrete type
- The interface method is the inverse of the valueof method, which puts a reflect. Value reverts to an interface value: The information of the type and value stored in value is packaged into an interface to represent and return;
Y,ok: = V.interface (). The type of (float64)//Y is asserted as float64
Fmt. Println (y)
The above can be abbreviated to this:
Fmt. Println (V.interface ())//fmt. Println's going to get it back.
- Reflection object of Channel type: Trysend (), Tryrecv () method;
- The Isnil () method determines whether the value saved by the reflected object is nil;
4. The export method of the original object can be called dynamically by reflection:
V: = reflect. ValueOf (&x) m: = V.methodbyname ("Show") in: = []reflect. value{ reflect. ValueOf (+), reflect. ValueOf (323),}out: = M.call (in) //For arguments available Callslice method
5. The original object can be modified by reflection:
- Principle:
- Because the functions and methods of the go are all copies of the formal parameters, similarly, when an object is reflected, the parameter is saved as an interface object and passed as a parameter (copy), the interface variable is non-settable, and the returned value is non-settable, An error occurred while calling the set method on it;
- The Canset method of value is used to test the settablity nature of a value, which is somewhat like unaddressability, but more strictly, describing the ability of a reflective object to modify the actual stored value that is created by it. Settability is determined by whether the reflected object holds the original item.
- Therefore, if you want to modify an object by reflection, you must first pass the object's pointer to reflect. ValueOf (&x), so that the resulting value object holds a copy of the original object pointer, only find the value pointed to by the pointer to modify the original object, through the Elem () method you can obtain a saved the original object of the value object, The value object at this time is settable;
for a settable value reflection object, such as d: = reflect. ValueOf (&x). Elem ():
- D.canaddr () method: Determine if it can be taken address
- D.Canset () method: Determine if it can be taken address and can be modified
The way that a settable value reflects an object to access and modify its corresponding variable:
- Mode 1: By converting the reflected object back to the original object type pointer, and then modifying the pointer directly
- PX: = D.addr (). Interface (). (*int)
- The first step is to call the addr () method, which returns a value that holds a pointer to the variable.
- The interface () method is then called on value to return a interface{}, which contains a pointer to the variable.
- Finally, if we know the type of the variable, we can use the type's assertion mechanism to force the ring to the normal type pointer by using the interface{} type of interface. So we can update the variables with this normal pointer.
- Mode 2: Can be modified directly by the set () method
- D.set (reflect. ValueOf (4))
- Setint, Setuint, SetString and SetFloat methods: D.setint (3), note: Although methods such as Setint () can work as long as the underlying data type of the parameter variable is a signed integer, it cannot be a reference to interface{} Type of reflect. Value
- Summary: Value reflects the object in order to modify what they represent must have the address of these things
var x float64 = 3.4p: = reflect. ValueOf (&X)//Note here: The X address is passed in! Fmt. Println (P.type ()) //*float64fmt. Println (P.canset ()) //false here the p is just the pointer, still is the non-settable V: = P.elem ()//At this time the V saved xfmt. Println (V.canset ())//true v.setfloat (7.1) fmt. Println (V.interface ())//7.1fmt. PRINTLN (x)//7.1
Although reflection can override the export rules of the Go language to read members that are not exported in the struct, You cannot modify these non-exported members . Because only the fields that are exported in a struct are settable.
Type T struct { A int B string}t: = t{23, "Skidoo"}s: = Reflect. ValueOf (&t). Elem () Typeoft: = S.type ()//Put S. Type () returns the type object copied to Typeoft,typeoft is also a reflection. For I: = 0; I < S.numfield (); i++ { F: = S.field (i)//iteration s of each domain, note that each domain is still reflection. FMT. Printf ("%d:%s%s =%v\n", I, Typeoft.field (i). Name, F.type (), F.interface ())//Extract the name of each domain}//0:a int = 23//1:b string = Skidoos. Field (0). Setint (//s.field) (0). Set (reflect. ValueOf (S.field)) (1). SetString ("Sunset Strip") fmt. Println ("T is now", T) //t are now {Sunset Strip}
6. The Reflection library provides built-in functions for make and new operations, such as reflect. The Makefunc () method allows you to implement functions like "generics":
- Define a generic template algorithm function that adapts to different data types, and then use reflect. Makefunc () method, you can bind any function type variable to a generic template algorithm function (specifying the same function body for a series of function objects);
Package Mainimport ("reflect" "strings" "FMT")//General algorithm function Body template func Add (args []reflect. Value) (Results []reflect. Value) {If len (args) = = 0 {return Nil}var R reflect. Valueswitch Args[0]. Kind () {case reflect. Int:n:=0for _,a:=range Args{n+=int (A.int ())}r = reflect. VALUEOF (n) case reflect. STRING:SS: = Make ([]string,0,len (args)) for _,s:=range Args{ss = append (ss,s.string ())}r=reflect. ValueOf (Strings. Join (SS, ""))}results = append (results,r) return}func makeadd (T interface{}) {fn:=reflect. ValueOf (T). Elem () V:=reflect. Makefunc (FN. Type (), add)//Save the type of the original function variable and the generic algorithm function to the same value Fn.set (v) /////The original function pointer variable to V, so that it obtains the function body}func main () { ///define function variable, Undefined function Body var intadd func (x, y int) Intvar stradd func (A, B string) Stringmakeadd (&intadd) makeadd (&stradd) fmt. Println (Intadd (12,23)) //35fmt. Println (Stradd ("Hello,", "world!"))//hello, world!}
Finally, the reflection has a certain effect on performance, such as high performance requirements, you should use reflection carefully!