【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 mainimport ("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.TypeobjectType := 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)})
可以看下结构体Method中Func的定义,有这么一句注释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 mainimport ("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 = namereturn nil
}func (a *dog) GetName() (string, error) {fmt.Println("Getting name!")return a.name, nil
}func main() {var tudou = &dog{name: "tudou"}// 获取reflect.ValueobjectValue := reflect.ValueOf(tudou)// 根据方法名获取method,执行CallobjectValue.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的Name和Index是一一对应的
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),有兴趣的同学可以留意观察下
相关文章:
【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)…...
Teleport
从官网中获取到的代码如下 App.vue <template><div class"outer"><h3>Tooltips with Vue 3 Teleport</h3><div><MyModal /></div></div> </template> <script setup> import MyModal from "./My…...
flutter与原生 相互通信实战
一、原生和flutter 通信 ios 通信类 CommonUtil.swift import Foundation import Flutterpublic class CommonUtil {public static func emitEvent(channel: FlutterMethodChannel, method: String, type: String, errCode: Int32?, errMsg: String?, data: Any?){safeMa…...
结构光相机原理
结构光相机原理...
ubuntu安装Anaconda
下载 Anaconda 进入 Ubuntu,自己新建下载路径,输入以下命令开始下载 注意,如果不是 x86_64,需要去镜像看对应的版本(https://mirrors.bfsu.edu.cn/anaconda/archive/?CM&OA) wget https://mirrors.…...
【RNA structures】RNA转录的重构和前沿测序技术
文章目录 RNA转录重建1 先简单介绍一下测序相关技术2 Map to Genome Methods2.1 Step1 Mapping reads to the genome2.2 Step2 Deal with spliced reads2.3 Step 3 Resolve individual transcripts and their expression levels 3 Align-de-novo approaches3.1 Step 1: Generat…...
4、Kafka 消费者
5.1 Kafka 消费方式 5.2 Kafka 消费者工作流程 5.2.1 消费者总体工作流程 5.2.2 消费者组原理 Consumer Group(CG):消费者组,由多个consumer组成。形成一个消费者组的条件,是所有消费者的groupid相同。 • 消费者组内…...
CSS3 渐变
CSS3 渐变可以让你在两个或多个指定的颜色之间显示平稳的过渡。 CSS3渐变有两种类型:线性渐变(Linear Gradients)和径向渐变(Radial Gradients)。 线性渐变(Linear Gradients): 线性…...
【Python 千题 —— 基础篇】分割有效信息
题目描述 题目描述 有时候我们需要截取字符串以获取有用的信息,比如对于字符串 “日期:2010-10-29”,我们需要截取后面的 10 个字符来获取日期,以便进行进一步分析。编写一个程序,输入一个字符串,然后输出…...
webrtc基于DTLS的端口复用技术
DTLS协议: DTLS(Datagram Transport Layer Security)数据包安全传输协议,用于在不可靠的数据包传输协议上(如UDP)提供数据的安全传输。 UDP多路复用: 一个UDP多路复用,被用来处理共享同一个UDP端口的多个并发的UDT连接。类似同一个tcp port上创建多个socket connec…...
【2024秋招】2023-9-20 度小满信贷系统平台部二面
1 面试官的部门介绍 我们部门是信贷系统平台部,主要是为度小满做一个服务,你应该也接触过信用卡,跟这种差不多,用户可以打进我们的系统申请一个额度,整个部门的规模大概是400-500人左右,我个人来自平台数据…...
【Django 04】Serialization 序列化的高级使用
序列化器 serializers 序列化器的作用 序列化将 queryset 和 instance 转换为 json/xml/yaml 返回给前端 反序列化与序列化则相反 定义序列化器 定义类,继承自 Serializer 通常新建一个 serializers.py 文件 撰写序列化内容 suah as 目前只支持 read_only 只…...
【前端学习】—变量类型和计算(五)
【前端学习】—变量类型和计算(五) 一、JS中使用typeof能得到哪些类型 字符串(String):表示文本数据,用单引号或双引号括起来。 数字(Number):表示数值数据,包括整数和浮点数。 布尔值(Boolean):表示真或假(true或false)的逻辑值。 空值(Null):表示一个空…...
QT中窗口自绘制效果展示
项目中需要使用QT进行窗口自绘,前期先做一下技术探索,参考相关资料代码熟悉流程。本着代码是最好的老师原则,在此记录一下。 目录 1.运行效果 2.代码结构 3.具体代码 1.运行效果 2.代码结构 3.具体代码 myspeed.pro QT core gui…...
Android Studio 直接获取Spinner的值
最近做一个小demo 使用Spinner下拉框来让用户选择地区、周数(第1-12周) 然后参考了一下别人的文章 这里引用这位博主博文: AndroidStudio使用spinner控件并添加监听(极简)_安卓spinner监听事件_天王老子来了我也不…...
渗透测试工具(3)Burpsuite
笔记目录 渗透测试工具(1)wireshark渗透测试工具(2)Nmap渗透测试工具(3)Burpsuite 1.简介 是Web应用程序测试,请求的拦截和修改,扫描web应用程序漏洞,以暴力破解登陆表单,执行会话令牌等多种的随机性检查。 (1)模块介绍 ①Intercept:用于显示和修改Ht…...
大数据之LibrA数据库系统上下电管理
系统上电 操作场景 系统管理员进行例行维护停机后需要重新启动服务器与FusionInsight LibrA集群。如果安装双机Manager,上电后HA将确定主备管理节点。系统启动完成后需要启动依赖集群运行的上层业务。 对系统的影响 系统上电完成以前集群不可用。 前提条件 获…...
Node.js、Vue的安装与使用(Linux OS)
Vue的安装与使用(Linux OS) Node.js的安装Vue的安装Vue的使用 操作系统:Ubuntu 20.04 LTS Node.js的安装 安装Node.js Node.js官方下载地址 1.选择合适的系统架构(可通过uname -m查看)版本安装 2.下载文件为tar.xz格…...
SparkSQL入门
概述 两种模式 Spark on Hive: 语法是Spark SQL语法,实际上是在IDEA上编写java叠加SQL的代码。 Hive on Spark: 只是替换了Hadoop的MR,改为了Spark的计算引擎。 发展历史 RDD > DataFrame > DataSet: 都有惰性机制,遇…...
AC修炼计划(AtCoder Regular Contest 167)
传送门:AtCoder Regular Contest 167 - AtCoder 再次感谢樱雪喵大佬的题解,讲的很详细,Orz。 大佬的博客链接如下:Atcoder Regular Contest 167 - 樱雪喵 - 博客园 (cnblogs.com) 第一题很签到,就省略掉了。 第二题…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...
实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...
