上一篇文章 说到了 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()的更多相关文章

  1. Javscript调用iframe框架页面中函数的方法

    Javscript调用iframe框架页面中函数的方法,可以实现iframe之间传值或修改值了, 访问iframe里面的函数: window.frames['CallCenter_iframe'].h ...

  2. QT源码解析(七)Qt创建窗体的过程,作者“ tingsking18 ”(真正的创建QPushButton是在show()方法中,show()方法又调用了setVisible方法)

    前言:分析Qt的代码也有一段时间了,以前在进行QT源码解析的时候总是使用ue,一个函数名在QTDIR/src目录下反复的查找,然后分析函数之间的调用关系,效率实在是太低了,最近总结出一个更简便的方法, ...

  3. 中文乱码在java中URLEncoder.encode方法要调用两次解决

    中文乱码在java中URLEncoder.encode方法要调用两次解决 一.场景: 1.我在客户端要通过get方式调用服务器端的url,将中文参数做utf-8编码,需要在js中两次的进行编码,服务器 ...

  4. day26——tyoe元类与object的联系、反射、函数与方法的区别、双下方法

    day26 type元类与object联系 type 获取对象从属于的类 python 中一切皆对象, 类在某种意义上也是一个对象,python中自己定义的类,以及大部分内置类,都是由type元类(构 ...

  5. Matlab中函数定义方法

    Matlab自定义函数的六种方法 n1.函数文件+调用函数(命令)文件:需单独定义一个自定义函数的M文件: n2.函数文件+子函数:定义一个具有多个自定义函数的M文件: n3.Inline:无需M文件 ...

  6. Javascript中函数的四种调用方式

    一.Javascript中函数的几个基本知识点: 1.函数的名字只是一个指向函数的指针,所以即使在不同的执行环境,即不同对象调用这个函数,这个函数指向的仍然是同一个函数. 2.函数中有两个特殊的内部属 ...

  7. python记录_day18 反射 判断函数与方法

    一.三个内置函数 1.issubclass(a, b)  判断a类是否是b类的子类 class Foo: pass class Zi(Foo): pass class Sun(Zi): pass pr ...

  8. JavaScript 中函数的定义和调用

    3种函数定义方式: 1.使用关键字 function 来声明并定义函数 function myFunction(a, b) { return a * b; } 调用函数: var x = myFunc ...

  9. javascript中函数的四种调用模式详解

    介绍函数四种调用模式前,我们先来了解一下函数和方法的概念,其实函数和方法本质是一样,就是称呼不一样而已.函数:如果一个函数与任何对象关系,就称该函数为函数.方法:如果一个函数作为一个对象属性存在,我们 ...

随机推荐

  1. usb_control_msg函数用法和说明

    usb_control_msg是没有用到urb的在USB中简单进行发送和接收的一种机制,用于少量的数据通信.原型为:  程序代码 linux+v2.6.35/drivers/usb/core/mess ...

  2. ioctl函数详细说明(网络)

    ioctl 函数 本函数影响由fd 参数引用的一个打开的文件. #include<unistd.h> int ioctl( int fd, int request, .../* void ...

  3. 编程入门python之定义函数【转】

    编程入门python之定义函数 零基础学编程by学哥 2017-02-06 10:51 今天讲python函数. 输入参数求三角形或圆形或长方形的面积 先输入1个参数:形状类型 1=三角形 2=圆形 ...

  4. Axure RP 快速原型设计工具

       Axure RP是美国Axure Software Solution公司旗舰产品,是一个专业的快速原型设计工具,让负责定义需求和规格.设计功能和界面的专家能够快速创建应用软件或Web网站的线框图 ...

  5. MongoDB存储基础教程

    一.MongoDB简介 1. mangodb是一种基于分布式.文件存储的非关系型数据库 2. C++写的,性能高 3. 为web应用提供可扩展的高性能数据存储解决方案 4. 所支持的格式是json格式 ...

  6. 页面跳转时中间参数保存(memcache/cookie)

    2014年1月19日 17:30:27 我这篇文章就说了一句话:用cookie保存页面间跳转时的参数 情景: 客服在后台操作的时候,经常从列表页进入到编辑页,编辑完信息后,还要自动返回之前的列表页 问 ...

  7. device-pixel-radio

    移动web开发之像素和DPR 今天看到一个面试题,为iphone6s的自适应,答案是@media(min-device-width:414px) and(max-device-width:736px) ...

  8. 文件时间戳修改touch和查看stat和ls --time

    查看文件时间戳命令:stat awk.txtFile: `awk.txt'Size: 20  Blocks: 8  IO Block: 4096  regular fileDevice: 801h/2 ...

  9. 2018ACM/ICPC 青岛现场赛 E题 Plants vs. Zombies

    题意: 你的房子在0点,1,2,3,...,n(n<=1e5)点每个点都有一颗高度为0的花,浇一次水花会长a[i]. 你有一个机器人刚开始在你家,最多走m步,每一步只能往前走或者往后走,每走到一 ...

  10. 解决 Delphi XE5 写Android程序的No resource identifier found for attribute... 错误【转】

    原文:http://www.hxhlb.cn/article/32142aaeb67bbc05379369c3.html 那一天,我装上了RAD Studio XE5. 当天晚上,我就写了一个小小的A ...