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}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/9644.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络 TCP/IP体系 数据链路层

一. 数据链路层的基本概念 数据链路层主要负责节点之间的通信&#xff0c;确保从物理层接收到的数据能够准确无误地传输到网络层。 数据链路层使用的信道主要有以下两种类型: 点对点信道: 这种信道使用一对一的点对点通信方式。广播信道: 这种信道使用一对多的广播通信方式,…

使用注解装配Bean

&#xff01;&#xff01;&#xff01;仅用作学习笔记记录&#xff01;&#xff01;&#xff01; 一、一些概念&#xff1a; 1.定义Bean的注解&#xff1a; 在实际开发中分别使用Repository、Service与Controller对实现类进行标注。 2.注入Bean组件装配的注解 Autowired默认…

csa文件管理账号管理练习

1、查看/etc/passwd文件的第18-20行内容&#xff0c;并将找到的内容存储至/home/passwd文件中&#xff08;head&#xff0c;tail&#xff0c;>,>>&#xff09; # head -num 显示文件头num行 # tail -num &#xff1a;显示文件的最后num行 # 输出重定向 > # 使用…

软考高级架构 - 8.1 - 系统质量属性与架构评估 - 超详细讲解+精简总结

第8章 系统质量属性与架构评估 软件系统属性包括功能属性和质量属性&#xff0c;而软件架构重点关注质量属性。 8.1 软件系统质量属性 8.1.1 概述 软件系统的质量反映了其与需求的一致性&#xff0c;即&#xff1a;软件系统的质量高低取决于它是否能满足用户提出的需求&#…

初见Linux:基础开发工具

前言&#xff1a; 这篇文章我们将讲述Linux的基本开发工具&#xff0c;以及讨论Linux的生态圈&#xff0c;最后再了解vim开发工具。 Yum&#xff1a; YUM&#xff08;Yellowdog Updater Modified&#xff09;是一个在Linux系统中用于管理软件包的工具&#xff0c;特别是在基于…

电信基站智能计量新方案:DJSF1352双通讯直流计量电表——安科瑞 丁佳雯

随着信息技术的飞速发展和5G时代的到来&#xff0c;电信基站作为信息传输的重要基础设施&#xff0c;其能耗管理和运营效率成为各大运营商关注的焦点。为了应对日益增长的能耗需求和复杂的运维挑战&#xff0c;采用高效、智能的计量方案显得尤为重要。在这样的背景下&#xff0…

Pytorch cuda版本选择(高效简洁版)

简而言之 Pytorch cuda版本选择 只需要低于cuda驱动版本即可&#xff0c;cuda驱动版本查看命令是nvidia-smi, nvcc -V 是runtimeapi版本可以不用管 1.只要看cuda驱动版本 安装pytorch 选择cuda版本&#xff0c;只要看你电脑cuda驱动版本即可。 2.选择依据 pytorch中cuda版本只…

全网最详细的项目管理完整方案!破解项目管理难题,解决方案一网打尽!

在现代企业中&#xff0c;项目管理愈发复杂&#xff0c;尤其是项目规模扩大、团队多元化的情况下&#xff0c;项目管理的难度逐渐上升。当前&#xff0c;企业在项目管理中面临以下主要问题&#xff1a; 信息碎片化&#xff1a;项目数据和文件分散在不同部门和系统中&#xff0…

数据库的使用05:不规范的写法与操作记录

一、写SQL带数据库名 【严禁】sql写成 select * from databasename.dbo.tablename 【原因】生产环境的databsename不一定和开发环境的databsename一样 【正确写法】select * from tablename 二、不合理的表设计 【改善方法】C#小结&#xff1a;数据库中数据表的设计原则、技…

YOLO11改进 | 融合改进 | C3k2引入多尺度分支来增强特征表征【全网独家 附结构图】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 本文给大家带来的教程是将YOLO11的C3k2替…

三维测量与建模笔记 - 3.1 相机标定基本概念

成像领域有多个标定概念 笔记所说的相机标定主要是指几何标定。 相机几何模型基于小孔成像原理&#xff0c;相关文章很多&#xff0c;上图中R t矩阵是外参矩阵&#xff08;和相机在世界空间中的位姿相关&#xff09;&#xff0c;K矩阵是内参矩阵&#xff08;和相机本身参数相关…

安卓/华为手机恢复出厂设置后如何恢复照片

绝大多数安卓用户都会经历过手机恢复出厂设置&#xff0c;部分用户可能没有意识到手机恢复出厂设置可能会导致数据丢失。但是&#xff0c;当您在 云盘上进行备份或在设备上进行本地备份时&#xff0c;情况就会有所不同&#xff0c;并且当您将 安卓手机恢复出厂设置时&#xff0…

丹摩征文活动 |【AI落地应用实战】文本生成语音Parler-TTS + DAMODEL复现指南

目录 一、Parler-TTS简介1.1、TTS 模型1.2、Parler-TTS 二、Parler-TTS复现流程2.1、创建实例2.2、配置代码与环境2.3、配置预训练模型2.4、Parles-TTS使用 Parler-TTS 是一个由 Hugging Face 开源的文本生成语音 (Text-to-Speech, TTS) 模型。它的设计目的是生成高质量的语音输…

【QT项目】QT6项目之基于C++的通讯录管理系统(联系人/学生管理系统)

目录 一.项目背景 二.创建工程 工程创建 添加文件 联系人类 功能类 三.功能实现 联系人类 person.cpp person.h 查 查询按钮槽函数 返回按钮槽函数 findperson.cpp: 增 addperson.cpp: 删 deleteperson.cpp&#xff1a; 改 changeperson.cpp&#xff1a…

一文详谈领域驱动设计实践

作者&#xff1a;泊静 阿里云开发者 导读 本文作者结合在团队的实践过程&#xff0c;分享了自己对领域驱动设计的一些思考。 了解过领域驱动设计的同学都知道&#xff0c;人们常常把领域驱动设计分为两部分&#xff1a;战术设计和战略设计。这两个概念本身都是抽象的&#xff…

单链表OJ思路

目录 前言 一、移除链表元素 二、反转链表 三、链表的中间结点 四、返回倒数第k个结点 五、合并两个有序链表 六、链表分割 七、链表的回文结构 八、相交链表 九、环形链表 十、环形链表|| 十一、随机链表的赋值 前言 11道单链表OJ题的解题思路。 一、移除链表元素 链接&#…

数据结构与算法——Java实现 54.力扣1008题——前序遍历构造二叉搜索树

不要谩骂以前的自己 他当时一个人站在雾里也很迷茫 ​​​​​​​ ​​​​​​​ ​​​​​​​—— 24.11.6 1008. 前序遍历构造二叉搜索树 给定一个整数数组&#xff0c;它表示BST(即 二叉搜索树 )的 先序遍历 &#xff0c;构造树并返回其根。 保证 对于给定…

【Qt聊天室客户端】单聊与群聊

1. 区分单聊和群聊 逻辑分析 具体实现逻辑 主窗口完善判断单聊还是群聊的逻辑 单聊会话详情入口中&#xff0c;设置头像和昵称 2. 删除好友 直接找到删除好友的按钮&#xff0c;然后实现其删除逻辑即可 具体实现 无法删除好友BUG处理 问题复现&#xff0c;点击好友删除后&…

1.集合体系补充(1)

1.接口式引用 集合的构造&#xff0c;我们需要采用接口类型引用的的方式&#xff0c;这样做的好处就是方便根据业务或者设计上的变化&#xff0c;快速更换具体的实现。 事实上&#xff0c;Java集合设计体系者也是支持我们这样做的&#xff0c;并且集合体系的设计也是如此的。 创…

枚举及优化(一)

第1题 百钱买百鸡 查看测评数据信息 百钱买百鸡问题&#xff1a;公鸡五文钱一只&#xff0c;母鸡三文钱一只&#xff0c;小鸡三只一文钱&#xff0c;用 100 文钱买 100只鸡&#xff0c;公鸡、母鸡、小鸡各买多少只&#xff1f;本程序要求解的问题是&#xff1a;给定一个正整…