Golang reflect.method usage

introduction

This problem first appeared when looking at the 6.824 labrpc, which used reflect.method. At that time, the understanding of reflection was still only in reflect.type and reflect.value, so I didn't understand it very well in some key places. When I checked the information, I was surprised to find that there was no blog about the usage of this thing except for the official documents, so I decided to record a blog after understanding it to help friends with the same problem.

text

reflect.method is actually used to get the definition of the interface function after the function is passed to interface{}, and then we can operate this reflect.method.

Let's look at a simple implementation, and then look at its definition:

type Person struct {
    
    
	Name string
	Age int
	Sex string
}

type tool struct {
    
    
	cap string
	key string
}

func (t *tool) print(){
    
    
	fmt.Println(t.cap, t.key)
}

func (p Person) Say(msg string){
    
    
	fmt.Println("hello," , msg)
}

func (p Person) PrintInfo(t *tool){
    
    
	t.cap = "green"
	t.key = "long"
	fmt.Printf("姓名:%s, 年龄:%s, 性别:%s, 参数tool内容:%s %s\n", p.Name, p.Age, p.Sex, t.key, t.cap)
}

type service struct {
    
    
	servers map[string]reflect.Method
	rcvr reflect.Value
	typ reflect.Type
}

func MakeService(rep interface{
    
    }) (*service) {
    
    
	ser := service{
    
    }
	ser.typ = reflect.TypeOf(rep)
	ser.rcvr = reflect.ValueOf(rep)
	// name返回其包中的类型名称,举个例子,这里会返回Person,tool
	name := reflect.Indirect(ser.rcvr).Type().Name()
	fmt.Println(name)
	ser.servers = map[string]reflect.Method{
    
    }
	fmt.Println( ser.typ.NumMethod(), ser.typ.Name())
	for i:=0 ; i < ser.typ.NumMethod(); i++ {
    
    
		method := ser.typ.Method(i)
		mtype := method.Type
		//mtype := method.Type	// reflect.method
		mname := method.Name	// string
		fmt.Println("mname : ", mname)
		ser.servers[mname] = method
	}
	return &ser
}

func main(){
    
    
	p1 := Person{
    
    "Rbuy", 20, "男"}
	// 得到这个对象的全部方法,string对应reflect.method
	methods := MakeService(p1)
	// 利用得到的methods来调用其值
	methname := "PrintInfo"
	if method, ok := methods.servers[methname]; ok{
    
    
		// 得到第一个此method第1参数的Type,第零个当然就是结构体本身了
		replyType := method.Type.In(1)
		replyType = replyType.Elem()	// Elem会返回对
		// New returns a Value representing a pointer to a new zero value for the specified type.
		replyv := reflect.New(replyType)
		function := method.Func
		function.Call([]reflect.Value{
    
    methods.rcvr,replyv})
		// 此时我们已经拿到了返回值
	}
}

MakeServiceWhat we do is to get all of it through interface{} reflect.method, and then return a interface{}mapping of this member name to method, so that we can call this function in other places, and we only need to pass in an input parameter. Called.

After reading this code, you will know reflect.methodthe function. We might as well think about what is the role of reflection? The definition of reflection in the Go language Bible is this: without knowing the type at compile time, variables can be updated, values ​​can be viewed at runtime, methods can be called, and their layout can be manipulated directly . Of course this is based on the interface. In layman's terms, reflection allows us to directly get its dynamic value and dynamic type in an interface{}, and it can also modify the members of this dynamic value and call its function, then value can let us call the value, and the method of course is to call Function, so it makes sense, it will be covered with rain and dew.

It is worth noting here that callthe parameters and return values ​​are all []reflect.valuetypes, which requires attention.

Let's take reflect.valuea brief look at the definition:

type Method struct {
    
    
    // Name is the method name.
    // PkgPath is the package path that qualifies a lower case (unexported)
    // method name.  It is empty for upper case (exported) method names.
    // The combination of PkgPath and Name uniquely identifies a method
    // in a method set.
    // See http://golang.org/ref/spec#Uniqueness_of_identifiers
    Name    string	
    PkgPath string

    Type  Type  // method type
    Func  Value // func with receiver as first argument
    Index int   // index for Type.Method
}

According to this definition, it can be seen that reflect.methodit is actually functionan encapsulation of variables, and it can also be known that the methods that Value can use can of course also be used.

Only based on this variable we can do a lot of things, for example, we Typecan take out any number of parameter types of the method input, so as to build a type of this type reflect.value. We can also call this method directly, of course, to Valuedo this.

So in short, a function's Typeand Valuecan do Methodcan be done, that's what it does.

As for its actual function, the usage I have seen is to implement a simple RPC between native multi-coroutines, which can return all the methods of the incoming structure through the interface for direct call by other coroutines. As for other uses, it is waiting for everyone to discover.

Guess you like

Origin blog.csdn.net/weixin_43705457/article/details/109107288