Reflection (reflection) refers to the ability to dynamically acquire program structure information (meta-information) at run time, which is a feature supported by static type languages such as Java, Golang, and so on. Here is a detailed introduction of Golang reflection related knowledge
Type and interface (Types and interfaces)
Type MyInt Intvar i intvar J MyInt
I is of type int, J is Myint type. Although the i,j underlying types are int, they are of different types and no conversions can be assigned to each other.
Interface type interface, which represents a collection of methods, any concrete (non-interface) value can be assigned to interface as long as the interface method is implemented
Reader is the interface that wraps the basic Read Method.type Reader Interface {Read (P []byte) (n int, err error)}/ /writer is the interface that wraps the basic Write method.type Writer Interface {write (P []byte) (n int, err error)} var r io. Readerr = OS. Stdinr = Bufio. Newreader (r) r = new (bytes. Buffer)//And so on
The static type of the R variable is IO. Reader, the actual type may be file, buffer type
interface{} Special interface type, there is no method, so any type can be assigned to it
The representation of an interface
var r io. Readerr = new (bytes. Buffer)
The specific type of r variable is IO. Reader, the actual type is bytes. Buffer, how is Golang implemented at run time?
A variable of type interface stores 2 information, a value, type pair <value,type> pair:
var r io. Readertty, err := os. OpenFile ("/dev/tty", os. o_rdwr, 0) if err != nil { return nil, err}r = tty
interface type R <value, type> pair is ( tty
, *os. File
) /span>
Of course the value TTY of the R variable does not only implement IO. The Read method in the reader interface also implements IO. Write method in writer, so you can do
Type assertion, which attempts to convert R to IO. Writer
var w io. Writerw = R. (IO. Writer)
At this point, the <value,type>pair of the interface variable w is ( tty
, *os.File
), that is, r,w the underlying value is the same, you can expose different methods by different type.
Continue discussion
var empty interface{}empty = w//The type assertion is not required here, because any type can be considered as a way to implement the empty interface
Interface variable empty <value,type> pair for ( tty
, *os.File
)
Reflection
1. Reflection goes from interface value to Reflection object. (Interface type---> Reflection type (reflect. Value,reflect. Type))
Reflection, you can get specific information about the interface type variable (<value,concrete type>)
Golang Reflector Package for reflect
ValueOf returns a new Value initialized to the concrete value//stored in the interface I. ValueOf (NIL) returns the Zer o value.func ValueOf (i interface{}) Value//Get pair value//TypeOf returns the reflection Type that represents the dynamic Type of i.//If i is a nil interface value, TYPEOF returns Nil.func TypeOf (i interface{}) type//Get concrete type in pair
eg
var r io. Readerr = OS. Stdin//<value, type>: <os. Stdin, *os. File>rvalue: = reflect. ValueOf (r) Rtype: = reflect. TypeOf (R) fmt. Println ("Value:", RValue) fmt. Println ("type:", Rtype) Output: value: &{0xc04205a000}//pointer type: *os. Filevar f float64f = 1.234fmt. Println ("F Value:", reflect. ValueOf (f)) fmt. Println ("F Type:", reflect. TypeOf (f)) output: F value:1.234f type:float64
2. Reflection goes from Reflection object to interface value. Reflection type (reflect. Value,reflect. Type)--Interface types
Type user struct { id int name string Age int}func (U user) reflectcallfunc () { Fmt. Println ("Reflect learn")}user := user{1, "test", 13}var i interface{}i = useruvalue := reflect. ValueOf (i) utype := reflect. TypeOf (i) fmt. Println ("uvalue: ", Uvalue) fmt. The Println (Uvalue.interface ()) //is converted to the Interface type, Unpack uvalue.interface (). (User) fmt. Println (Uvalue.type ()) fmt. Println ("uvalue,string: ", Utype.string ()) fmt. Println ("utype: ", Utype.name ()) For i := 0; i < utype.numfield (); i+ + { //get field Information field := utype.field (i) value := uvalue.field (i). Interface () fmt. Printf ("%s: %v = %v\n", field. Name, field. Type, value)}for i : = 0; i < utype.nummethod (); i++ {// Get method information method := utype.method (i) fmt. Printf ("method[%d] = %s \n", I,method. Name)}fmt. Println (Uvalue.kind ()) fmt. Println (Utype.kind ())
3. To modify a reflection object, the value must is settable. modifying variables by Reflection
var x float64 = 3.4v: = reflect. ValueOf (x) fmt. Println ("Settability of V:", V.canset ())//print:settability of V:falsev. SetFloat (7.1)//Error:will panic.
Reasons for non-modifiable:we pass a copy ofx
toreflect.ValueOf
, so the interface value created as the argument toreflect.ValueOf
is a copy ofx
, notx
itself
Workaround, pass the pointer!!
var x float64 = 3.4p: = reflect. ValueOf (&x)//Note:take the address of x.fmt.println ("type of P:", P.type ()) fmt. Println ("Settability of P:", P.canset ()) Print:type of P: *float64settability of P:false//why? P non-set,p points can be set,p point to the content that is *p, how to get p point of content?
Reflect. The Elem method of value that can get the content that the value points to
V: = P.elem () fmt. Println ("Settability of V:", V.canset ())//settability of V:truev. SetFloat (7.1) fmt. Println (V.interface ())//7.1fmt. PRINTLN (x)//7.1
4. Structs Reflection Operation Example
Type T struct {A int B string}t: = t{23, "Skidoo"}s: = Reflect. ValueOf (&t). Elem () Typeoft: = S.type () for I: = 0; I < S.numfield (); i++ {f: = S.field (i) fmt. Printf ("%d:%v%s%s =%v\n", I, S.kind (), Typeoft.field (i). Name, F.type (), F.interface ())}fmt. Println ("Canset:", S.canset ()) S.field (0). Setint (S.field) (1). SetString ("Sunset Strip") fmt. Println ("After Change:", S.interface ())
5. Calling methods via reflect
Type user struct { id int name string Age int}func (U user) reflectcallfunc () { Fmt. Println ("Reflect learn")}func (U user) funchasargs (name string, age int) { fmt. Println ("funchasargs name: ", name, ", age:", age, "and origal User.Name: ", u.name)}func (U user) funcnoargs () { fmt. Println ("Funcnoargs")}user := user{1, "test", 13}uvalue := reflect. ValueOf (user) Utype := reflect. TypeOf (user) M1 := uvalue.methodbyname ("Funchasargs") m2 := uvalue.methodbyname ("FuncNoArgs") ) M ,b := utype.methodbyname ("Funcnoargs") args := []reflect. Value{reflect. ValueOf ("Xiong"), reflect. ValueOf (}M1). Call (args) Args = make ([]reflect. Value,0) m2. Call (args) fmt. Println ("M1:", M1) FMT. Println ("m2:", m2) fmt. Printf ("m:% #v, isfound:%v\n", M,b) fmt. PRINTLN (M1)