反射中调用函数

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

  1. package main
  2. import "fmt"
  3. func hello() {
  4. fmt.Println("Hello world!")
  5. }
  6. func main() {
  7. hl := hello
  8. hl()
  9. }

prints:

  1. hello world!

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


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

prints:

  1. fv is reflect.Func? true
  2. hello world!

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

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

prints:

  1. i = 20
  2. result: 20
  3. ------------------------------------------------------------------

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


golang 反射中调用方法的更多相关文章

  1. Lua中“.”调用方法与“:”调用方法的区别

    Lua中“.”调用方法与“:”调用方法的区别:                                                                             ...

  2. Xlua文件在热更新中调用方法

    Xlua文件在热更新中调用方法 public class news : MonoBehaviour { LuaEnv luaEnv;//定义Lua初始变量 void Awake() { luaEnv ...

  3. C# 知识点笔记:IEnumerable<>的使用,利用反射动态调用方法

    IEnumerable<T>的使用 创建一个IEnumerable对象 List<string> fruits = new List<string> { " ...

  4. C# 反射之调用方法谈

    反射的定义 反射提供了描述程序集.模块和类型的对象(Type 类型). 可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性. 如果代码中使用了特性 ...

  5. 利用java反射动态调用方法,生成grid数据

    项目中需要java后台查询并组装前台grid的数据,数据行数不定,数据行定义不定,开始用了最原始的方法,写了几百行,就是前台需要什么字段后台拼接什么字段,java代码冗余量非常大,并且不够灵活,一旦前 ...

  6. golang通过反射动态调用方法

    func Call(m map[string]interface{}, name string, params ...interface{}) ([]reflect.Value, error) { f ...

  7. SpringCache @Cacheable 在同一个类中调用方法,导致缓存不生效的问题及解决办法

    由于项目需要使用SpringCache来做一点缓存,但自己之前没有使用过(其实是没有听过)SpringCache,于是,必须先学习之. 在网上找到一篇文章,比较好,就先学习了,地址是: https:/ ...

  8. Golang循环中调用go func参数异常分析

    项目中,需要循环调用API服务器列表,在循环中使用go func创建协程时遇到了参数失灵的现象. 具体代码如下所示: for _, apiServerAddr := range apiServerAd ...

  9. 使用dubbo引用和发布服务时出现的异常:HTTP状态500 - 请求处理失败; 嵌套异常是com.alibaba.dubbo.rpc.RpcException:无法在服务cn.e3mall.service.ItemService中调用方法getTbItemById。使用dubbo版本2.5.3在消费者...

    异常情况如下: 从异常看,主要是因为TbItem没有序列化: 分析问题: 表现层调用服务端时返回了一个TbItem对象即Java对象,此时这个对象远程调用拿过来必须进行序列化,要进行网络传输必须先要把 ...

随机推荐

  1. Oracle 监听hang住

    1.数据库正常启动: [oracle@db ~]$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.4.0 Production on Sat Aug 24 ...

  2. python学习之路(19)

    匿名函数 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便. 在Python中,对匿名函数提供了有限支持.还是以map()函数为例,计算f(x)=x2时,除了定义一个f(x) ...

  3. C++入门经典-例5.15-回收动态内存的一般处理步骤

    1:正确的步骤应该是如下代码所示: // 5.15.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostrea ...

  4. shiro的web.xml的配置

    <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class&g ...

  5. hdfs、zookeepeer之HA模式

    HA简介 1.所谓HA,即高可用(high available) 2.消除单点故障,避免集群瘫痪,hdfs中namenode保存了整个集群的元数据,如果namenode所在机器宕机,则整个集群瘫痪,H ...

  6. 线程同步synchronized理解

    Synchronized 理解 用法:1.同步方法.2.同步静态方法.3同步代码块. 理解Synchronized 的关键是“锁” (原理在最后) 同步代码有“锁”者执行.所谓的锁必须是同一个.静态的 ...

  7. vue组件化之模板优化及注册组件语法糖

    vue组件化之模板优化及注册组件语法糖 vue组件化 模板 优化  在 https://www.cnblogs.com/singledogpro/p/12054895.html 这里我们对vue.js ...

  8. 正则表达式中常用的模式修正符有i、g、m、s、x、e详解

    正则表达式中常用的模式修正符有i.g.m.s.x.e等.它们之间可以组合搭配使用. 它们的作用如下: //修正符:i 不区分大小写的匹配; //如:"/abc/i"可以与abc或a ...

  9. vuefor循环

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  10. 学习笔记 - MarkDown 语法

    学习参考网址:https://www.appinn.com/markdown/index.html # **gitskill** ## 标题 ># 这是 H1 >## 这是 H2 > ...