当前位置: 首页 > news >正文

Golang--反射

1、概念

反射可以做什么?

  • 反射可以在运行时动态获取变量的各种信息,比如变量的类型,类别等信息
  • 如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)
  • 通过反射,可以修改变量的值,可以调用关联的方法。
  • 使用反射,需要import("reflect")



反射相关的函数

  • reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型(结构体类型)
  • reflect.ValueOf变量名),获取变量的值,返回reflect.Value类型(reflect.Value是一个结构体类型),通过reflect.Value,可以获取到关于该变量的很多信息。

type Type interface {// Kind返回该接口的具体分类Kind() Kind// Name返回该类型在自身包内的类型名,如果是未命名类型会返回""Name() string// PkgPath返回类型的包路径,即明确指定包的import路径,如"encoding/base64"// 如果类型为内建类型(string, error)或未命名类型(*T, struct{}, []int),会返回""PkgPath() string// 返回类型的字符串表示。该字符串可能会使用短包名(如用base64代替"encoding/base64")// 也不保证每个类型的字符串表示不同。如果要比较两个类型是否相等,请直接用Type类型比较。String() string// 返回要保存一个该类型的值需要多少字节;类似unsafe.SizeofSize() uintptr// 返回当从内存中申请一个该类型值时,会对齐的字节数Align() int// 返回当该类型作为结构体的字段时,会对齐的字节数FieldAlign() int// 如果该类型实现了u代表的接口,会返回真Implements(u Type) bool// 如果该类型的值可以直接赋值给u代表的类型,返回真AssignableTo(u Type) bool// 如该类型的值可以转换为u代表的类型,返回真ConvertibleTo(u Type) bool// 返回该类型的字位数。如果该类型的Kind不是Int、Uint、Float或Complex,会panicBits() int// 返回array类型的长度,如非数组类型将panicLen() int// 返回该类型的元素类型,如果该类型的Kind不是Array、Chan、Map、Ptr或Slice,会panicElem() Type// 返回map类型的键的类型。如非映射类型将panicKey() Type// 返回一个channel类型的方向,如非通道类型将会panicChanDir() ChanDir// 返回struct类型的字段数(匿名字段算作一个字段),如非结构体类型将panicNumField() int// 返回struct类型的第i个字段的类型,如非结构体或者i不在[0, NumField())内将会panicField(i int) StructField// 返回索引序列指定的嵌套字段的类型,// 等价于用索引中每个值链式调用本方法,如非结构体将会panicFieldByIndex(index []int) StructField// 返回该类型名为name的字段(会查找匿名字段及其子字段),// 布尔值说明是否找到,如非结构体将panicFieldByName(name string) (StructField, bool)// 返回该类型第一个字段名满足函数match的字段,布尔值说明是否找到,如非结构体将会panicFieldByNameFunc(match func(string) bool) (StructField, bool)// 如果函数类型的最后一个输入参数是"..."形式的参数,IsVariadic返回真// 如果这样,t.In(t.NumIn() - 1)返回参数的隐式的实际类型(声明类型的切片)// 如非函数类型将panicIsVariadic() bool// 返回func类型的参数个数,如果不是函数,将会panicNumIn() int// 返回func类型的第i个参数的类型,如非函数或者i不在[0, NumIn())内将会panicIn(i int) Type// 返回func类型的返回值个数,如果不是函数,将会panicNumOut() int// 返回func类型的第i个返回值的类型,如非函数或者i不在[0, NumOut())内将会panicOut(i int) Type// 返回该类型的方法集中方法的数目// 匿名字段的方法会被计算;主体类型的方法会屏蔽匿名字段的同名方法;// 匿名字段导致的歧义方法会滤除NumMethod() int// 返回该类型方法集中的第i个方法,i不在[0, NumMethod())范围内时,将导致panic// 对非接口类型T或*T,返回值的Type字段和Func字段描述方法的未绑定函数状态// 对接口类型,返回值的Type字段描述方法的签名,Func字段为nilMethod(int) Method// 根据方法名返回该类型方法集中的方法,使用一个布尔值说明是否发现该方法// 对非接口类型T或*T,返回值的Type字段和Func字段描述方法的未绑定函数状态// 对接口类型,返回值的Type字段描述方法的签名,Func字段为nilMethodByName(string) (Method, bool)// 内含隐藏或非导出方法
}

 

2、对基本数据类型反射

反射相关的函数

  • reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型(结构体类型)
  • reflect.ValueOf变量名),获取变量的值,返回reflect.Value类型(reflect.Value是一个结构体类型),通过reflect.Value,可以获取到关于该变量的很多信息。
package mainimport("fmt""reflect"
)func testReflect(i interface{}){//1、调用TypeOf()函数,返回reflect.Type类型的变量reType := reflect.TypeOf(i)fmt.Println("reType=",reType)  //int,但不代表reType是int,只是代表reType是int的变量,reType类型是reflect.Typefmt.Printf("reType的类型是:%T\n",reType) //*reflect.Type//2、调用VauleOf()函数,返回reflect.Value类型的变量reValue := reflect.ValueOf(i)fmt.Println("reValue=",reValue) // 119,但不代表reValue是119,只是代表reValue是119的变量,reValue类型是reflect.Valuefmt.Printf("reValue的类型是:%T\n",reValue) //reflect.Value//如果想获取reValue的数值,要调用Int()方法:返回reValue持有的的数值num2 := 80 + reValue.Int() //Int()方法返回reValue持有的的数值--直接用reValue是不行的,因为reValue是reflect.Value类型的变量,类型不匹配不能直接用,需要调用Int()方法fmt.Println("num2=",num2) // 199//reValue转成空接口i2 := reValue.Interface()//类型断言n := i2.(int)n2 := n + 100fmt.Println(n2)
}func main(){//对基本数据类型进行反射//定义一个int类型的变量var num int = 119//获取变量的类型	testReflect(num)
}

3、 对结构体进行反射

与基本数据类型同理

package mainimport("fmt""reflect"
)type Student struct{Name stringAge int
}func testReflect(i interface{}){//1、调用TypeOf()函数,返回reflect.Type类型的变量reType := reflect.TypeOf(i)fmt.Println("reType=",reType) //main.Studentfmt.Printf("reType的类型是:%T\n",reType) //*reflect.rtype//2、调用VauleOf()函数,返回reflect.Value类型的变量reValue := reflect.ValueOf(i)fmt.Println("reValue=",reValue) //{张三 18}fmt.Printf("reValue的类型是:%T\n",reValue) //reflect.Value //reValue转成空接口i2 := reValue.Interface()//类型断言n,flag := i2.(Student)if flag{//断言成功fmt.Println(n.Name,' ',n.Age) // 张三 18}else{//断言失败fmt.Println("类型断言失败")}
}func main(){//对结构体数据类型进行反射//定义一个结构体类型的变量stu := Student{Name: "张三",Age: 18,}//获取变量的类型	testReflect(stu)
}

4、获取变量的类别

类型和类别的区别:

  • 类别是一个大的方向:例如不同的结构体类型都属于struct这个结构体类别
  • 类型是具体某一个类型:例如不同的结构体类型属于不同的类型
     


 

package mainimport("fmt""reflect"
)type Student struct{Name stringAge int
}func testReflect(i interface{}){//1、调用TypeOf()函数,返回reflect.Type类型的变量reType := reflect.TypeOf(i)//2、调用VauleOf()函数,返回reflect.Value类型的变量reValue := reflect.ValueOf(i)//3、获取变量的类别--Typefmt.Println("类别:",reType.Kind()) //类别:struct//4、获取变量的类别--Valuefmt.Println("类别:",reValue.Kind()) //类别:struct//获取变量的类型://reValue转成空接口i2 := reValue.Interface()//类型断言:n,flag := i2.(Student)if flag{fmt.Printf("类型:%T",n) // 类型:main.Student}
}func main(){//对结构体数据类型进行反射//定义一个结构体类型的变量stu := Student{Name: "张三",Age: 18,}//获取变量的类型	testReflect(stu)
}

 5、通过反射修改变量

package mainimport("fmt""reflect"
)type Student struct{Name stringAge int
}func testReflect(i interface{}){reValue := reflect.ValueOf(i)//通过SetInt()修改值reValue.Elem().SetInt(200)
}func main(){var num int = 100testReflect(&num) //传入的是地址,才能修改值fmt.Println(num) // 200
}

6、通过反射操作结构体的属性和方法

package main
import ("fmt""reflect"
)type Student struct{Name stringAge int
}
func (s Student) APrint(){fmt.Println("Name:",s.Name)fmt.Println("Age:",s.Age)
}func (s Student) BGetSum(n1,n2 int) int{return n1 + n2
}func (s *Student) CSet(name string,age int){s.Name = names.Age = age
}//定义函数操作结构体进行反射操作
func TestStudentReflect(a interface{}){//a转成reflect.Valueval := reflect.ValueOf(a)//通过reflect.Value类型操作结构体内部的字段:n1 := val.NumField() // 获取结构体字段的数量fmt.Println(n1)//通过遍历--获取具体的字段for i := 0; i < n1; i++{fmt.Printf("第%d个字段的值是:%v\n",i,val.Field(i)) //获取第i个字段的值}//通过reflect.Value类型操作结构体内部的方法:n2 := val.NumMethod() // 获取结构体方法的数量fmt.Println(n2)//调用方法//调用方法,方法的首字母必须大写才能有对应的反射的访问权限//方法的顺序按照ASCII码表的顺序进行排序的,对应索引从0开始,依次类推val.Method(0).Call(nil) //调用第0个方法var params []reflect.Valueparams = append(params,reflect.ValueOf(11))params = append(params,reflect.ValueOf(19))result := val.Method(1).Call(params)fmt.Println(result[0].Int()) //30
}//通过反射改变结构体的值
func TestStudentReflect2(a interface{}){//a转成reflect.Valueval := reflect.ValueOf(a)n := val.Elem().NumField() // 获取结构体字段的数量fmt.Println(n)//直接修改字段的值val.Elem().Field(0).SetString("李四")val.Elem().Field(1).SetInt(21)//调用上面定义的方法--Cset()var params []reflect.Valueparams = append(params,reflect.ValueOf("王五"))params = append(params,reflect.ValueOf(22))val.Method(2).Call(params) //CSet方法
}func main(){a := Student{Name: "张三",Age: 20,}TestStudentReflect(a)fmt.Println("")TestStudentReflect2(&a)fmt.Println(a) //{王五 22}
}

相关文章:

Golang--反射

1、概念 反射可以做什么? 反射可以在运行时动态获取变量的各种信息&#xff0c;比如变量的类型&#xff0c;类别等信息如果是结构体变量&#xff0c;还可以获取到结构体本身的信息(包括结构体的字段、方法)通过反射&#xff0c;可以修改变量的值&#xff0c;可以调用关联的方法…...

ABAP:SET CURSOR FIELD设置鼠标焦点

SET CURSOR FIELD <字段名>&#xff1a;设置鼠标焦点到该字段 SET CURSOR 设置到鼠标焦点列还是行 SET CURSOR LINE 设置鼠标焦点到行 GET CURSOR field <字段名> &#xff1a;这个相对应的获取鼠标焦点得到的字段...

【专题】2024年全球生物医药交易报告汇总PDF洞察(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p38191 在当今复杂多变的全球经济环境下&#xff0c;医药行业正面临着诸多挑战与机遇。2024 年&#xff0c;医药行业的发展态势备受关注。 一方面&#xff0c;全球生物医药交易活跃&#xff0c;2021 - 2023 年的交易中&#xff0c;已…...

LabVIEW气体检测系统

随着工业化进程的加速&#xff0c;环境污染问题愈加严峻&#xff0c;尤其是有害气体的排放对人类生存环境构成了严重威胁。为了更好地监测这些有害气体&#xff0c;开发一个高效、准确且易于操作的气体检测系统显得尤为重要。LabVIEW软件开发的气体检测系统&#xff0c;采用激光…...

LeetCode78. 子集(2024秋季每日一题 58)

给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的 子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[],[1],[2],[1,2],[3…...

推荐一款功能强大的视频修复软件:Apeaksoft Video Fixer

Apeaksoft Video Fixer是一款功能强大的视频修复软件&#xff0c;专门用于修复损坏、不可播放、卡顿、画面失真、黑屏等视频问题。只需提供一个准确且有效的样本视频作为参考&#xff0c;该软件就能将受损视频修复到与样本视频相同的质量。该软件目前支持MP4、MOV、3GP等格式的…...

Golang--网络编程

1、概念 网络编程&#xff1a;把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统&#xff0c;从而使众多的计算机可以方便地互相传递信息、共享数据、软件、数据信息等资源。 客户端&#xff08;Client&#xff09; 客户端是请求服务…...

区块链技术在数字版权管理中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 区块链技术在数字版权管理中的应用 区块链技术在数字版权管理中的应用 区块链技术在数字版权管理中的应用 引言 区块链技术概述 …...

WPS单元格重复值提示设置

选中要检查的所有的单元格 设置提示效果 当出现单元格值重复时&#xff0c;重复的单元格就会自动变化 要修改或删除&#xff0c;点击...

Scala 的包及其导入

Scala使用包来创建用于模块化程序的命名空间。通过在Scala文件的顶部声明一个或多个包名称可以创建包&#xff0c;另一种声明包的方式是使用0&#xff0c;这种方式可以嵌套包&#xff0c;并且提供更好的范围与封装控制。对于包的导入&#xff0c;Scala与Java的区别之一便是&…...

架构师备考-概念背诵(软件工程)

软件工程 软件开发生命周期: 软件定义时期:包括可行性研究和详细需求分析过程,任务是确定软件开发工程必须完成的总目标,具体可分成问题定义、可行性研究、需求分析等。软件开发时期:就是软件的设计与实现,可分成概要设计、详细设计、编码、测试等。软件运行和维护:就是…...

DIP switch是什么?

**‌DIP开关&#xff08;DIP switch&#xff09;‌&#xff0c;也称为指拨开关&#xff0c;是一种可以人工调整的开关&#xff0c;通常以标准双列直插封装&#xff08;DIP&#xff09;的形式出现。**DIP开关一般设计在印刷电路板上&#xff0c;配合其他电子元件使用&#xff0c…...

【销帮帮-注册_登录安全分析报告-试用页面存在安全隐患】

联通支付注册/登录安全分析报告 前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨…...

2024年下半年系统分析师论文

2024年下半年11月份系统分析师考试论文 1、静态测试工具和方法 可以从代码桌前检查&#xff0c;代码审查&#xff0c;代码走查组织文章 2、DevOps开发 可以从开发&#xff0c;运维&#xff0c;测试的自动化协作入手&#xff0c;跨部门沟通需求也算 3、业务流程分析 从BPR…...

【计算机网络】万字详解 UDP 和 TCP

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. UDP1.1 UDP 报文格式1.1.1 源端口/目的端口1.1.2 报文长度1.1.3 校验和 2. TCP2.1 TCP 报文结构2.2 TCP 特…...

创建者模式之【建造者模式】

建造者模式 概述 将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于&#xff1a;某个对象的构建过程复杂的情况。由于实现了构建和…...

电商系统中,如何解决部分商品在短时间大量访问的单一热点问题?------Range范围分片

在电商系统中&#xff0c;部分商品在短时间内遭受大量访问的单一热点问题&#xff0c;可能引发服务器压力增大、响应速度变慢、甚至系统崩溃等问题。为了解决这一问题&#xff0c;可以采取以下策略&#xff1a; 一、增加服务器容量和带宽 提升硬件性能&#xff1a;为了应对高…...

利用VMware workstation pro 17安装 Centos7虚拟机以及修改网卡名称

通过百度网盘分享的文件&#xff1a;安装虚拟机必备软件 链接&#xff1a;https://pan.baidu.com/s/1rbYhDh8x1hTzlSNihm49EA?pwdomxy 提取码&#xff1a;omxy 123网盘 https://www.123865.com/s/eXPrVv-UsKch 提取码:eNcy 先自行安装好VMware workstation pro 17 设置虚拟机…...

前端 性能优化 (图片与样式篇)

文章目录 前端能够做哪些图片优化?1、减小图片体积2、图片缓存服务工作线程 (Service Workers)缓存IndexDB缓存图片LocalStorage缓存 3、图片懒加载使用 loading"lazy" 属性 4、不同分辨率下使用不同的图片5、使用webp格式的图片6、配置图片CDN7、减少图片和动图的使…...

A021基于Spring Boot的自习室管理和预约系统设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

Spring Boot + MyBatis 集成支付宝支付流程

Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例&#xff08;电脑网站支付&#xff09; 1. 添加依赖 <!…...

webpack面试题

面试题&#xff1a;webpack介绍和简单使用 一、webpack&#xff08;模块化打包工具&#xff09;1. webpack是把项目当作一个整体&#xff0c;通过给定的一个主文件&#xff0c;webpack将从这个主文件开始找到你项目当中的所有依赖文件&#xff0c;使用loaders来处理它们&#x…...