反射中调用函数

众所周知,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方法达到同样的效果:


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. Link-Cut Tree(LCT) 教程

    目录 前置知识 介绍 Access FindRoot MakeRoot Split Link Cut 关于Splay中操作的一点说明: 模板 前置知识 请先对树链剖分和Splay有所了解.LCT基于树 ...

  2. [CSP-S模拟测试]:线性代数(模拟)

    题目传送门(内部题113) 输入格式 第一行一个正整数$n$. 接下来$n$行,每行$n$个整数,描述$C$矩阵.保证输入的是一个林先森矩阵. 输出格式 若不可能实现,则输出一行$Impossible ...

  3. HTML5 localStorage setItem getItem removeItem

    HTML5 WEB存储中提供了两种客户端的数据存储方法:localStorage 还有sessionStorage localStorage: localStorage 方法存储的数据没有时间限制.第 ...

  4. __doPostBack function

    __doPostBack function Hi everyone. Today I am going to talk about the __doPostBack function, because ...

  5. vue父子组件

    vue父子组件 新建 模板 小书匠  为什么要厘清哪个是父组件,哪个是子组件? 一开始浏览器接收和要显示的数据非常少,此时无需划分区域进行布局.随着页面数据量的增加,如果单纯一个窗口来加载和显示数据, ...

  6. leetcode-easy-listnode-237 Delete Node in a Linked List

    mycode # Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # sel ...

  7. Python学习笔记:MySQL数据库连接和使用

    一.安装pymysql插件 直接在pycharm中安装即可. 二.使用 1.数据库插入操作 insert 注意: insert语句需要提交,使用commit() 如果报错,需要回滚.使用rollbac ...

  8. Activity启动模式分类(一)

    standerd 默认模式,每次启动Activity都会创建一个新的Activity实例. 比如:现在有个A Activity,我们在A上面启动B,再然后在B上面启动A,其过程如图所示: single ...

  9. 采用WPF技术开发截图程序

    前言  QQ.微信截图功能已很强大了,似乎没必要在开发一个截图程序了.但是有时QQ热键就是被占用,不能快速的开启截屏:有时,天天挂着QQ,领导也不乐意.既然是程序员,就要自己开发截屏工具,功能随心所欲 ...

  10. 查询处理Oracle锁表的问题

    --以下几个为相关表SELECT * FROM v$lock;SELECT * FROM v$sqlarea;SELECT * FROM v$session;SELECT * FROM v$proce ...