Golang invokes methods dynamically using Reflection reflect

  • 2020-06-23 00:36:26
  • OfStack

The concept of reflection in programming languages

In computer science, reflection is a category 1 application that is self-describing and self-controlling. In other words, such applications implement a mechanism to describe their behavior (ES4en-ES5en) and monitor their behavior (examination), and can adjust or modify the state and related semantics of their behavior according to the state and results of their behavior.

Each language has a different reflection model, and some languages don't support reflection at all. The Golang language implements reflection. The reflection mechanism is to dynamically call the methods and properties of an object at runtime. The official reflect package is reflective and can be used as long as the package is included.

To add one more, Golang's gRPC is also achieved by reflection.

The official package for Golang, reflect, implements runtime reflection (ES19en-ES20en reflection). Well done, it can be very powerful. Today, we're going to use reflect to make dynamic method calls...

Basic knowledge of

First, reflection is primarily related to the interface type of golang. A variable of type interface contains two Pointers: one to the type of the variable and one to the value of the variable. The two most commonly used functions are:


func main(){
 s := "hello world"
 fmt.Println(reflect.ValueOf(s))  // hello world
 fmt.Println(reflect.TypeOf(s))  // string
}

Among them,

reflect. ValueOf() return value type: ES37en. Value reflect.TypeOf () return value type: ES41en.Type

Create a variable

Next, we can use reflect to create variables dynamically:


func main(){
 var s string
 t := reflect.TypeOf(s)
 fmt.Println(t)         // string
 sptr := reflect.New(t)
 fmt.Printf("%s\n", sptr)    // %!s(*string=0xc00000e1e0)
}

Note that reflect. New() returns 1 pointer:

[

New returns a Value representing a pointer to a new zero value for the specified type. That is, the returned Value's Type is PtrTo(typ).

]

At this point, we can use reflect.Value.Elem () to get the actual value:


sval := sptr.Elem()  //  Return value type: reflect.Value

Then convert it to interface and do ES67en-ES68en:


ss := sval.interface().(string)
fmt.Println(ss)    //  An empty string 

The dynamic invocation

Suppose we have defined struct and implemented the following methods:


type M struct{}
type In struct{}
type Out struct{}
 
func (m *M) Example(in In) Out {
 return Out{}
}

We can then make the call by:


func main() {
 v := reflect.ValueOf(&M{})
 m := v.MethodByName("Example")
 in := m.Type().In(0)
 out := m.Type().Out(0)
 fmt.Println(in, out)
    
 inVal := reflect.New(in).Elem()
    //  Can be  inVal  to interface Then assign something like that... 
 rtn := m.Call([]reflect.Value{inVal})
 fmt.Println(rtn[0])
}

Registration method

Let's define another map struct that holds all of M's methods:


type Handler struct {
 Func  reflect.Value
 In   reflect.Type
 NumIn int
 Out  reflect.Type
 NumOut int
}

We can then traverse all the methods of structure M:


func main() {
 handlers := make(map[string]*Handler)
 v := reflect.ValueOf(&M{})
 t := reflect.TypeOf(&M{})
 for i := 0; i < v.NumMethod(); i++ {
 name := t.Method(i).Name
 //  According to  i  To get an instance, you can also use  v.MethodByName(name)  To obtain  
 m := v.Method(i)
 //  In this case we're just getting the first one 1 Input parameters and control 1 Return parameters 
 in := m.Type().In(0)
 out := m.Type().Out(0)
 handlers[name] = &Handler{
  Func:  m,
  In:   in,
  NumIn: m.Type().NumIn(),
  Out:  out,
  NumOut: m.Type().NumOut(),
 }
 }
}

Elem()

In learning reflect, we found that both reflect. Value and ES102en. Type provide the Elem() method.

The role of ES107en.Value.Elem (), which has been mentioned a little earlier, is primarily to return the value of 1 interface or pointer:

[

Elem returns the value that the interface v contains or that the pointer v points to. It panics if v's Kind is not Interface or Ptr. It returns the zero Value if v is nil.

]

reflect. Type. Elem() returns the type of an element of type 1 (Array, Map, Chan, etc.) :

[

Elem returns a type's element type. It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.

]

Related articles: