• golang 反射中调用方法


    反射中调用函数

    众所周知,golang中的函数是可以像普通的int、float等类型变量那样作为值的,例如:

    package main
    
    import "fmt"
    
    func hello() {
      fmt.Println("Hello world!")
    }
    
    func main() {
      hl := hello
      hl()
    }
    

    prints:

    hello world!
    

    既然函数可以像普通的类型变量一样可以的话,那么在反射机制中就和不同的变量一样的,在反射中函数和方法的类型(Type)都是reflect.Func,如果要调用函数的话,可以通过Value的Call方法,例如:

    
    func main() {
      hl := hello
      fv := reflect.ValueOf(hl)
      fmt.Println("fv is reflect.Func ?",fv.Kind() == reflect.Func)
      fv.Call(nil)
    }
    

    prints:

    fv is reflect.Func? true
    hello world!
    

    Value的Call方法的参数是一个Value的slice,对应的反射函数类型的参数,返回值也是一个Value的slice,同样对应反射函数类型的返回值。通过这个例子,相信你一看就明白了:

    func prints(i int) string {
      fmt.Println("i =",i)
      return strconv.Itoa(i)
    }
    
    func main() {
      fv := reflect.ValueOf(prints)
      params := make([]reflect.Value,1)  //参数
      params[0] := reflect.ValueOf(20)   //参数设置为20
      rs := fv.Call(params)              //rs作为结果接受函数的返回值
      fmt.Println("result:",rs[0].Interface().(string)) //当然也可以直接是rs[0].Interface()
    }
    

    prints:

    i = 20
    result: 20

    ------------------------------------------------------------------

    上面说了在反射中调用函数的例子,接下来我们要谈谈反射中方法的调用。函数和方法可以说其实本质上是相同的,只不过方法与一个“对象”进行了“绑定”,方法是“对象”的一种行为,这种行为是对于这个“对象”的一系列操作,例如修改“对象”的某个属性,例如如下:
    好了,现在类型和其对应的方法都已经准备好了,那接下来就是如何使用的问题了,我们有了上面调用函数的经验,只需要再了解一点知识就可以使用了,这一点知识就是MethodMethodByName的API,好了,现在都准备好了,我们就看看如何使用吧。

    type MyType struct {
    i int
    name string
    }

    func (mt *MyType) SetI(i int) {
    mt.i = i
    }

    func (mt *MyType) SetName(name string) {
    mt.name = name
    }

    func (mt *MyType) String() string {
    return fmt.Sprintf("%p",mt) + "--name:" + mt.name + " i:" + strconv.Itoa(mt.i)
    }



    func main() {
    myType := &MyType{22,"wowzai"}
    //fmt.Println(myType)     //就是检查一下myType对象内容
    //println("---------------")
    //mtV := reflect.ValueOf(&myType).Elem()
    //fmt.Println("Before:",mtV.MethodByName("String").Call(nil)[0])
    //params := make([]reflect.Value,1)
    //params[0] = reflect.ValueOf(18)
    //mtV.MethodByName("SetI").Call(params)
    //params[0] = reflect.ValueOf("reflection test")
    //mtV.MethodByName("SetName").Call(params)
    //fmt.Println("After:",mtV.MethodByName("String").Call(nil)[0])


    mtV := reflect.ValueOf(&myType).Elem()
    fmt.Println("Before:",mtV.Method(2).Call(nil)[0])
    params := make([]reflect.Value,1)
    params[0] = reflect.ValueOf(18)
    mtV.Method(0).Call(params)
    params[0] = reflect.ValueOf("reflection test")
    mtV.Method(1).Call(params)
    fmt.Println("After:",mtV.Method(2).Call(nil)[0])

    }

      

    需要注意的是上面打印的地址是对象在内存的地址,如果你也运行了这段代码,结果这个地址应该是不同的。

    咦,就这样结束了吗?当然不是,细心的读者会发现上面提到的Method好像没用到啊,恩,是的,聪明的你一看API的介绍我相信你就知道如何将上面的代码转换成用Method方法达到同样的效果:

  • 相关阅读:
    Java 数据库操作oracle增删改查,通用封装基于hashmap
    Python 自动化paramiko操作linux使用shell命令,以及文件上传下载linux与windows之间的实现
    Java利用 ganymedssh2build.jar来上传文件到linux以及下载linux文件以及执行linux shell命令
    Java Calendar and SimpleDateFormat 时间模块
    Java 读取properties
    Java java httpclient4.5 进行http,https通过SSL安全验证跳过,封装接口请求 get,post(formdata,json)封装,文件上传下载
    Python 基于request库的get,post,delete,封装
    更法第一 (zz)
    北京将投资707亿元建三条地铁新线 (zz.IS2120@BG57IV3)
    fgetws 讀取Unicode文件 (zz.IS2120@BG57IV3)
  • 原文地址:https://www.cnblogs.com/smallleiit/p/10840701.html
Copyright © 2020-2023  润新知