【Golang | reflect】利用反射实现方法的调用

这篇具有很好参考价值的文章主要介绍了【Golang | reflect】利用反射实现方法的调用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言

go语言中,如果某个数据类型实现了一系列的方法,如何批量去执行呢,这时候就可以利用反射里的func (v Value) Call(in []Value) []Value 方法。

// Call calls the function v with the input arguments in.
// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]).
// Call panics if v's Kind is not Func.
// It returns the output results as Values.
// As in Go, each input argument must be assignable to the
// type of the function's corresponding input parameter.
// If v is a variadic function, Call creates the variadic slice parameter
// itself, copying in the corresponding values.
func (v Value) Call(in []Value) []Value {
	v.mustBe(Func)
	v.mustBeExported()
	return v.call("Call", in)
}

Call方法实际使用时主要有以下两种调用方式:

方法1:使用reflect.Type.Method.Func.Call

package main

import (
	"fmt"
	"reflect"
)

type dog struct {
	name string
}

func (a *dog) Speak() {
	fmt.Println("speaking!")
}
func (a *dog) Walk() {
	fmt.Println("walking!")
}

func (a *dog) GetName() (string, error) {
	fmt.Println("Getting name!")
	return a.name, nil
}
func main() {
	var tudou = &dog{name: "tudou"}
	// 获取reflect.Type
	objectType := reflect.TypeOf(tudou)
	// 批量执行方法
	for i := 0; i < objectType.NumMethod(); i++ {
		fmt.Printf("Now method: %v is being executed...\n", objectType.Method(i).Name)
		// Call的第一个入参对应receiver,即方法的接受者本身
		ret := objectType.Method(i).Func.Call([]reflect.Value{reflect.ValueOf(tudou)})
		fmt.Printf("The return of method: %s is %v\n\n", objectType.Method(i).Name, ret)
	}
}

注:
1、这里说明下,为什么使用Func调用Call时第一个入参是对应receiver本身method.Func.Call([]reflect.Value{reflect.ValueOf(tudou)})
可以看下结构体MethodFunc的定义,有这么一句注释func with receiver as first argument

/*
 * The compiler knows the exact layout of all the data structures above.
 * The compiler does not know about the data structures and methods below.
 */

// Method represents a single method.
type Method struct {
	...
	Func  Value // func with receiver as first argument
	...
}

2、objectType.Method(i)返回的是一个Method结构体

方法2:使用reflect.Value.Method(index).Call

package main

import (
	"fmt"
	"reflect"
)

type dog struct {
	name string
}

func (a *dog) Speak() {
	fmt.Println("speaking!")
}

func (a *dog) SetName(name string) error {
	fmt.Println("Setting name!")
	a.name = name
	return nil
}

func (a *dog) GetName() (string, error) {
	fmt.Println("Getting name!")
	return a.name, nil
}

func main() {
	var tudou = &dog{name: "tudou"}
	// 获取reflect.Value
	objectValue := reflect.ValueOf(tudou)
	// 根据方法名获取method,执行Call
	objectValue.MethodByName("Speak").Call(nil)
	objectValue.MethodByName("SetName").Call([]reflect.Value{reflect.ValueOf("newName")})
	objectValue.MethodByName("GetName").Call(nil)
}

注:
1、不同于方法1,使用reflect.Value.Method直接调用Call,不需要使用receiver作为第一个入参。可以看下方法MethodByName的注释,有这么一句The arguments to a Call on the returned function should not include a receiver

// MethodByName returns a function value corresponding to the method
// of v with the given name.
// The arguments to a Call on the returned function should not include
// a receiver; the returned function will always use v as the receiver.
// It returns the zero Value if no method was found.
func (v Value) MethodByName(name string) Value {
	if v.typ == nil {
		panic(&ValueError{"reflect.Value.MethodByName", Invalid})
	}
	if v.flag&flagMethod != 0 {
		return Value{}
	}
	m, ok := v.typ.MethodByName(name)
	if !ok {
		return Value{}
	}
	return v.Method(m.Index)
}

2、objectValue.MethodByName("Speak")返回的是一个reflect.Value,这个跟方法1调用Method()有明显区别

3、另外值得留意的是,虽然方法2可以参考方法1的for循环批量执行method,但是reflect.Value似乎并没有直接提供方法获取每一个method的Name。但是我们可以根据Index借助reflect.Type.Method(Index).Name来获取Name,这是因为每一个method的NameIndex是一一对应的

type Method struct {
	// Name is the method name.
	Name string
	...
	Index int   // index for Type.Method
}

其实,注1里的方法func (v Value) MethodByName(name string) Value 里有一段也是根据这个对应关系实现的m, ok := v.typ.MethodByName(name) ... return v.Method(m.Index),有兴趣的同学可以留意观察下文章来源地址https://www.toymoban.com/news/detail-722382.html

到了这里,关于【Golang | reflect】利用反射实现方法的调用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入了解Golang中的反射机制

    目录 反射 反射的分类 值反射 类型反射 运行时反射 编译时反射 接口反射 结构体反射 常用函数 值反射 类型反射 值反射和类型反射的区别 结构体反射 示例代码         反射是指在程序运行时动态地检查和修改对象的能力。在Go语言中,通过反射可以在运行时检查变量的

    2024年02月06日
    浏览(35)
  • golang利用redis和gin实现保存登录状态,校验登录

    保存用户登录状态,一般常用的方式有两种 一、生成token,然后token保存到数据库用户表里面,每次登录的时候,自动更新,容纳后每次用的时候,去取出来校验,这种方式,数据库压力大,而且不是很灵活 二、每次登录生成token,然后token保存到Redis缓存中,每次都去校验,

    2024年01月20日
    浏览(32)
  • Go后端开发 -- 反射reflect && 结构体标签

    在计算机科学领域,反射是指一类应用,它们 能够自描述和自控制 。也就是说, 这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。 每种语言的反射

    2024年01月22日
    浏览(37)
  • Golang 中的反射,并用来获取数据类型

    Go语言提供了一种机制在运行中获取某个变量的类型,获取或修改变量的值,调用变量的方法。 示例代码如下 通过 reflect.Value 判断变量类型,并转换成 string 。 输出结果: 输出结果:

    2024年01月22日
    浏览(39)
  • golang反射获取结构体的值和修改值

    封装好就可以直接在service层使用了【自己手动复制粘贴】 或者嫌麻烦就放到【代码生成器】中,这样就不用每次都去写这个查询了

    2024年02月15日
    浏览(30)
  • golang实现webgis后端开发

    目录 前言 二、实现步骤 1.postgis数据库和model的绑定 2.将pg库中的要素转换为geojson (1)几何定义 (2)将wkb解析为几何类型 (3)定义geojson类型 (4)数据转换 (5)数据返回  2.前端传入的geojson储存到数据库 3、其他功能实现 总结         停更了接近一个月都在研究一门新语言gola

    2024年02月08日
    浏览(40)
  • Unity SRP 管线【第七讲:URP LOD实现以及Reflections反射探针】

    中文版:https://edu.uwa4d.com/lesson-detail/282/1314/0?isPreview=0 英文原版:https://catlikecoding.com/unity/tutorials/custom-srp/lod-and-reflections/ 1. 首先该组件需要将子类模型置于该组件物体子节点下 2. 可在单个LOD中设置其level的模型,并可设置它的距离范围,即可在不同距离下显示不同的模型 若

    2024年02月20日
    浏览(29)
  • golang实现rpc方法二:使用jsonrpc库【跨平台】

    首先在golang实现rpc方法一net/rpc库中实现了RPC方法,但是那个方法不是跨平台的,没法在其他语言中调用这个实现的RPC方法,接下来我们可以通过jsonroc库实现跨语言的RPC方法。俩种实现方式的代码其实也是差不多的,大差不差,只是调用的库不同。 serverrpc.go实现代码如下 cl

    2024年01月17日
    浏览(40)
  • golang实现rpc方法一:使用net/rpc库【不能跨平台】

    使用golang官方的net/rpc库实现RPC方法,使用http作为RPC的载体,通过http/net包监听客户端连接请求。 rpc服务端实现代码serverrpc.go如下 上述服务端程序运行之后,将会监听本地的8090端口,我们可以实现一个客户端程序,连接服务端并且实现RPC方法调用。 rpc客户端实现代码clientr

    2024年01月17日
    浏览(37)
  • golang调用智能合约,获取合约函数的返回值

    如果不是只读取数据的合约函数,需要异步的执行,因此并不能直接获取到合约函数的返回值,需要等到交易执行完毕,得到确认后才能获取到合约函数的返回值。而且合约函数返回值一般是通过事件日志获取到的。 这里给出一个例子来展示我是如何获取合约函数返回值的。

    2024年03月11日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包