Golang reflect.method 使用方法

引言

这个问题第一次出现在看6.824的labrpc时候,其中使用到了reflect.method。当时对反射的理解还只是停留在 reflect.type 和 reflect.value,所以在一些关键的地方读的并不是很懂。去查阅资料的时候惊奇的发现除了官方文档以外竟然没有一篇博客讲这个东西的用法,所以决定在搞懂以后记录一篇博客,以帮助有同样问题的朋友。

正文

reflect.method其实就是用于在函数传入interface{}以后拿到这个接口的函数的定义,然后我们就可以去操作这个reflect.method了。

我们来看一个简单的实现,再去看其定义:

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})
        // 此时我们已经拿到了返回值
    }
}

MakeService做的事情是通过interface{}拿到其全部的reflect.method,然后返回一个这个interface{}的成员名对应method的映射,这样我们就可以在其他地方去调用这个函数了,而且我们只需要传入一个入参就可以调用了。

看完这个代码基本就知道reflect.method的作用了。我们不妨想一想反射的作用是什么?Go语言圣经对于反射的定义是这样的:在编译时不知道类型的情况下,可更新变量,在运行时查看值,调用方法以及直接对它们的布局进行操作。当然这是基于interface来说的。通俗来说,反射可以让我们在一个interface{}中直接拿到其动态值和动态类型,同样可以修改这个动态值其中的成员和调用其函数,那么value可以让我们调用值,method当然就是调用函数了,这样也才说的通,雨露均沾嘛。

这里值得注意的是call的参数和返回值,都是[]reflect.value类型,这一点需要注意。

我们再来简单看一看reflect.value的定义:

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
}

根据这个定义也可以看出reflect.method其实就是function变量的一个封装罢了,也可以知道Value能用的方法method当然也可以使用了。

只不过基于这个变量我们能做的事情就有很多了,比如我们通过Type可以拿出方法入参的任意个参数类型,从而构建一个此类型的reflect.value。我们还可以直接调用这个method,当然是通过Value来做这个事情。

所以简而言之,一个functionTypeValue能做的事情Method都可以做,这就是它的作用。

至于它的实际作用,我看到的它的用法就是实现一个本机多协程间的简单RPC,可以通过接口返回传入结构体的全部方法,供其他协程直接调用。至于其他的用处,有待于大家发现啦。

原文链接: https://www.cnblogs.com/lizhaolong/p/16437216.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    Golang reflect.method 使用方法

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/396201

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月5日 下午2:12
下一篇 2023年4月5日 下午2:12

相关推荐