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中函数的四种调用模式详解
介绍函数四种调用模式前,我们先来了解一下函数和方法的概念,其实函数和方法本质是一样,就是称呼不一样而已.函数:如果一个函数与任何对象关系,就称该函数为函数.方法:如果一个函数作为一个对象属性存在,我们 ...
随机推荐
- MongoDB 之 Limit 选取 Skip 跳过 Sort 排序 MongoDB - 7
我们已经学过MongoDB的 find() 查询功能了,在关系型数据库中的选取(limit),排序(sort) MongoDB中同样有,而且使用起来更是简单 首先我们看下添加几条Document进来 ...
- 使用maven命令终端构建一个web项目及发布该项目
构建环境: maven版本:3.3.9 系统平台:Windows7 x64 JDK版本:1.7 构建步骤: 1.打开maven安装目录,在地址栏输入cmd进入命令窗口 2.输入命令mvn archet ...
- centos7切换启动内核
1.查看当前系统内核 uname -r 3.18.6-2.el7.centos.x86_64 查看可使用的内核列表 awk -F\' '$1=="menuentry " {prin ...
- MVC5使用EF6 Code First--创建EF数据模型(一)
此Web应用程序演示如何使用Entity Framework 6和Visual Studio 2015创建ASP.NET MVC 5应用程序.本教程使用“Code First ”即代码先行.有关如何在 ...
- java 异常 throw
throw UnsupportedOperationException(); //没有支持的操作NoSuchElementException(); //没有这样的元素
- PHP取整函数之ceil,floor,round,intval的区别
我们经常用到的PHP取整函数,主要是:ceil,floor,round,intval. ceil -- 进一法取整 说明 float ceil ( float value ) 返回不小于 value ...
- IOC入门
Spring六大模块 1.SpringCore spring的核心功能:IOC容器,解决对象的创建及依赖关系 2.SpringWeb spring对Web模块的支持 3.SpringDAO s ...
- Zookeeper+Curator 分布式锁
本来想着基于zk临时节点,实现一下分布式锁,结果发现有curator框架.PS:原声API真的难用,连递归创建path都没有? 配置curator maven的时候,md配置了好几个小时,最后发现集中 ...
- mysql多表查询,group by并将结果导出来csv文件
SQL手动操作得少,遇到一个CASE,就记录一个CASE吧. 今天遇到的是统计一个发布结果. 这个发布表中,有两个字段是外键,并且要求按其中一个外键,作group by操作, 最后,导出来excel能 ...
- [转] React 最佳实践——那些 React 没告诉你但很重要的事
前言:对很多 react 新手来说,网上能找到的资源大都是些简单的 tutorial ,它们能教会你如何使用 react ,但并不会告诉你怎么在实际项目中优雅的组织和编写 react 代码.用谷歌搜中 ...