Go - 反射中 函数 和 方法 的调用 - v.Call()
上一篇文章 说到了 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
反射中调用 方法
上面说了在反射中调用函数的例子,接下来我们要谈谈反射中方法的调用。函数和方法可以说其实本质上是相同的,只不过方法与一个“对象”进行了“绑定”,方法是“对象”的一种行为,这种行为是对于这个“对象”的一系列操作,例如修改“对象”的某个属性,如下所示:
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)
}
好了,现在类型和其对应的方法都已经准备好了,那接下来就是如何使用的问题了,我们有了上面调用函数的经验,只需要再了解一点知识就可以使用了,这一点知识就是 Method 和 MethodByName 的API,好了,现在都准备好了,我们就看看如何使用吧。
func main() {
myType := &MyType{22, "golang"}
//fmt.Println(myType) // 就是检查一下myType对象内容
//println("---------------") mtV := reflect.ValueOf(&myType).Elem()
// 也可以使用
//mtV := reflect.ValueOf(myType) 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])
}
prints:
Before: address:0x18245050--name:golang i i:22
After: address:0x18245050--name:reflection test i:18
需要注意的是上面打印的地址是对象在内存的地址,如果你也运行了这段代码,结果这个地址应该是不同的。
咦,就这样结束了吗?当然不是,细心的读者会发现上面提到的 Method 好像没用到啊,恩,是的,聪明的你一看 API 的介绍我相信你就知道如何将上面的代码转换成用 Method() 方法达到同样的效果:
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])
参考:
http://golang.org/doc/articles/laws_of_reflection.html
http://blog.csdn.net/wowzai/article/details/9327405
Go - 反射中 函数 和 方法 的调用 - v.Call()的更多相关文章
- Javscript调用iframe框架页面中函数的方法
Javscript调用iframe框架页面中函数的方法,可以实现iframe之间传值或修改值了, 访问iframe里面的函数: window.frames['CallCenter_iframe'].h ...
- QT源码解析(七)Qt创建窗体的过程,作者“ tingsking18 ”(真正的创建QPushButton是在show()方法中,show()方法又调用了setVisible方法)
前言:分析Qt的代码也有一段时间了,以前在进行QT源码解析的时候总是使用ue,一个函数名在QTDIR/src目录下反复的查找,然后分析函数之间的调用关系,效率实在是太低了,最近总结出一个更简便的方法, ...
- 中文乱码在java中URLEncoder.encode方法要调用两次解决
中文乱码在java中URLEncoder.encode方法要调用两次解决 一.场景: 1.我在客户端要通过get方式调用服务器端的url,将中文参数做utf-8编码,需要在js中两次的进行编码,服务器 ...
- day26——tyoe元类与object的联系、反射、函数与方法的区别、双下方法
day26 type元类与object联系 type 获取对象从属于的类 python 中一切皆对象, 类在某种意义上也是一个对象,python中自己定义的类,以及大部分内置类,都是由type元类(构 ...
- Matlab中函数定义方法
Matlab自定义函数的六种方法 n1.函数文件+调用函数(命令)文件:需单独定义一个自定义函数的M文件: n2.函数文件+子函数:定义一个具有多个自定义函数的M文件: n3.Inline:无需M文件 ...
- Javascript中函数的四种调用方式
一.Javascript中函数的几个基本知识点: 1.函数的名字只是一个指向函数的指针,所以即使在不同的执行环境,即不同对象调用这个函数,这个函数指向的仍然是同一个函数. 2.函数中有两个特殊的内部属 ...
- python记录_day18 反射 判断函数与方法
一.三个内置函数 1.issubclass(a, b) 判断a类是否是b类的子类 class Foo: pass class Zi(Foo): pass class Sun(Zi): pass pr ...
- JavaScript 中函数的定义和调用
3种函数定义方式: 1.使用关键字 function 来声明并定义函数 function myFunction(a, b) { return a * b; } 调用函数: var x = myFunc ...
- javascript中函数的四种调用模式详解
介绍函数四种调用模式前,我们先来了解一下函数和方法的概念,其实函数和方法本质是一样,就是称呼不一样而已.函数:如果一个函数与任何对象关系,就称该函数为函数.方法:如果一个函数作为一个对象属性存在,我们 ...
随机推荐
- 面积并+扫描线 覆盖的面积 HDU - 1255
题目链接:https://cn.vjudge.net/problem/HDU-1255 题目大意:中文题目 具体思路:和上一篇的博客思路差不多,上一个题求的是面积,然后我们这个地方求的是啊覆盖两次及两 ...
- LEARN HOW TO HACK
出处:https://www.hackerone.com/hacker101 什么是HACKER101? https://hacker101.com/Hacker101是一个视频,资源和实践活动的集合 ...
- nagios使用问题的解决方案
通过web界面修改某个服务时报错例如对某个服务进行临时安排其执行时间,或者不让它发警告,web页面上都有这样的设置.但是常常会有错误信息如下: Could not open command file ...
- poj2148
题意:给出若干个没有公共面积的多边形,几个多边形可能属于同一个国家,要求给这个地图染色,同一个国家用相同的颜色,相邻国家不能用相同颜色.问最少需要多少种颜色. 分析:计算几何+搜索.先判断哪些多边形是 ...
- 在 Ubuntu13.10 服务器中安装 Munin(监视工具)【转】
Munin 监测工具可检测所有的计算机,并记录好看到的计算机.通过图形Web界面的的方式显示所有信息.重点是即插即用的功能.完成安装后,大量的控插件会被打. 使用 Munin 您可以轻松地监视您的计算 ...
- angular有关网站
angular官网 https://v2.angular.cn/docs/ts/latest/ angular更新信息https://github.com/angular/angular/blob/m ...
- 有用的Python模块 - pprint
当想在终端打印一个很大的字典或者一个很长的列表时,总是被print打印出来的效果气懵在电脑前,现在有pprint就不用担心啦. 最直接的使用方式就是 import pprint pprint.ppri ...
- 第三届CCF软件能力认证
1.门禁系统 问题描述 涛涛最近要负责图书馆的管理工作,需要记录下每天读者的到访情况.每位读者有一个编号,每条记录用读者的编号来表示.给出读者的来访记录,请问每一条记录中的读者是第几次出现. 输入格式 ...
- Vue.js项目集成ElementUI
Vuejs实例-02Vue.js项目集成ElementUI Vuejs实例-02Vue.js项目集成ElementUI 0:前言 vue.js的UI组件库,在git上有多个项目,我见的使用者比较多 ...
- DSP 中关键字extern,cregister,Near ,Far,restrict,volatile
extern:extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.另外,extern也可用来进行链接指定. const: 可以 ...