【Go】二十、反射

文章目录

  • 1、反射
  • 2、对基本数据类型反射
  • 3、对结构体进行反射
  • 4、获取变量的类别
  • 5、通过反射修改基本类型变量的值
  • 6、通过反射操作结构体的属性和方法

1、反射

//核心包
import ("reflect")

通过反射:

  • 可以在运行时动态获取变量的类型、获取结构体的信息(字段、方法)
  • 可以修改变量的值,调用关联的方法

相关函数:

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

2、对基本数据类型反射

空接口没有任何方法,所以可以理解为所有类型都实现了空接口,也可以理解为可以把任何一个变量赋给空接口。有点像Object类

package main
import("fmt""reflect"
)
//利用一个函数,函数的参数定义为空接口:
func testReflect(i interface{}){//1.调用TypeOf函数,返回reflect.Type类型数据:reType := reflect.TypeOf(i)			//拿类型fmt.Println("reType:",reType)fmt.Printf("reType的具体类型是:%T",reType)fmt.Println()//2.调用ValueOf函数,返回reflect.Value类型数据:reValue :=reflect.ValueOf(i)fmt.Println("reValue:",reValue)		//拿值fmt.Printf("reValue的具体类型是:%T",reValue)fmt.Println()//如果真想获取reValue的数值,要调用Int()方法:返回v持有的有符号整数num := reValue.Int()fmt.Printf("Int()后的类型是:%T",num)fmt.Println()//reflect.Value类型数据,转回去,可先将reValue转成空接口,再用断言转型:i2 := reValue.Interface()//类型断言:n := i2.(int)n2 := n + 30fmt.Println(n2)
}func main(){//对基本数据类型进行反射://定义一个基本数据类型:var num int = 100testReflect(num)
}

运行:

在这里插入图片描述

注意点:如果有了reflect.Value类型,想转回原来的类型,可以用reflect.Value类型的Interface方法,转回空接口类型,再断言转型,回到int类型

在这里插入图片描述

3、对结构体进行反射

package main
import("fmt""reflect"
)
//利用一个函数,函数的参数定义为空接口:
func testReflect(i interface{}){//1.调用TypeOf函数,返回reflect.Type类型数据:reType := reflect.TypeOf(i)fmt.Println("reType:",reType)fmt.Printf("reType的具体类型是:%T",reType)fmt.Println()//2.调用ValueOf函数,返回reflect.Value类型数据:reValue :=reflect.ValueOf(i)fmt.Println("reValue:",reValue)fmt.Printf("reValue的具体类型是:%T",reValue)fmt.Println()//reValue转成空接口:i2 := reValue.Interface()//类型断言:n,flag := i2.(Student)if flag == true {//断言成功fmt.Printf("学生的名字是:%v,学生的年龄是:%v",n.Name,n.Age)}}
//定义学生结构体:
type Student struct{Name stringAge int
}
func main(){//对结构体类型进行反射://定义结构体具体的实例:stu := Student{Name : "丽丽",Age : 18,	}//反射testReflect(stu)
}

运行:

在这里插入图片描述

4、获取变量的类别

在上面reflect.Type和reflect.Value类型对象的基础上,获取类别(Student是类型,其类别是struct结构体)。相关方法:

reflect.Type.Kind()
reflect.Value.Kind()

在这里插入图片描述

package main
import("fmt""reflect"
)
//利用一个函数,函数的参数定义为空接口:
func testReflect(i interface{}){//空接口没有任何方法,所以可以理解为所有类型都实现了空接口,也可以理解为我们可以把任何一个变量赋给空接口。//1.调用TypeOf函数,返回reflect.Type类型数据:reType := reflect.TypeOf(i)//2.调用ValueOf函数,返回reflect.Value类型数据:reValue :=reflect.ValueOf(i)//获取变量的类别://(1)reType.Kind()k1 := reType.Kind()fmt.Println(k1)//(2)reValue.Kind()k2 := reValue.Kind()fmt.Println(k2)//获取变量的类型://reValue转成空接口:i2 := reValue.Interface()//类型断言:n,flag := i2.(Student)if flag == true {//断言成功fmt.Printf("结构体的类型是:%T",n)}
}
//定义学生结构体:
type Student struct{Name stringAge int
}
func main(){//对结构体类型进行反射://定义结构体具体的实例:stu := Student{Name : "丽丽",Age : 18,	}testReflect(stu)
}

运行:

在这里插入图片描述
类型Type和类别Kind的区别:

var num int = 10 num的Type是int , Kind也是int 
ar stu Studentstu的 Type是 pkg1.Student , Kind是struct

5、通过反射修改基本类型变量的值

调用reflect.Value的相关方法,SetInt、SetBoolean等等

package main
import("fmt""reflect"
)
//利用一个函数,函数的参数定义为空接口:
func testReflect(i interface{}){//空接口没有任何方法,所以可以理解为所有类型都实现了空接口,也可以理解为我们可以把任何一个变量赋给空接口。reValue :=reflect.ValueOf(i)//通过SetInt()来改变值:reValue.Elem().SetInt(40)}
func main(){//对基本数据类型进行反射://定义一个基本数据类型:var num int = 100testReflect(&num) //传入指针地址fmt.Println(num)	//40
}

注意,是改基本类型变量,值拷贝,要传入地址:

testReflect(&num) 

因为传入的是一个指针类型,想调用reflect.Value的相关方法,对上面的reValue 变量也得再转一下:

reValue.Elem().SetInt(40)

在这里插入图片描述

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

和Java一样,获取所有的变量和所有的方法,调用方法,方法的首字母必须大写才能有对应的反射的访问权限。相关方法:

  • NumField:获取结构体字段的总数
  • Field:获取结构体的某一个字段,传i序号0、1、2
  • NumMethod:获取结构体中方法的数量
  • Method:获取结构体中的某一个方法,传i序号0、1、2
  • Call,反射调用方法,形参是一个切片,即调用方法的形参
package main
import("fmt""reflect"
)
//定义一个结构体:
type Student struct{Name stringAge int
}
//给结构体绑定方法:
func (s Student) CPrint(){fmt.Println("调用了Print()方法")fmt.Println("学生的名字是:",s.Name)
}
func (s Student) AGetSum(n1,n2 int) int{fmt.Println("调用了AGetSum方法")return n1 + n2
}
func (s Student) BSet(name string,age int){s.Name = names.Age = age
}//定义函数操作结构体进行反射操作:
func TestStudentStruct(a interface{}){//a转成reflect.Value类型:val := reflect.ValueOf(a)//通过reflect.Value类型操作结构体内部的字段个数:n1 := val.NumField()fmt.Println(n1)		//2//遍历-获取具体的字段的值:for i := 0; i < n1;i++{fmt.Printf("第%d个字段的值是:%v",i,val.Field(i))}fmt.Println()//通过reflect.Value类型操作结构体内部的方法个数:n2 := val.NumMethod()fmt.Println(n2)//调用自定义结构体的CPrint()方法://调用方法,方法的首字母必须大写才能有对应的反射的访问权限//方法的顺序按照ASCII的顺序排列的,a,b,c,,,,,,索引:0,1,2,,,,,val.Method(2).Call(nil)	//nil给反射的那个方法传空参//调用AGetSum方法://定义Value的切片:var params []reflect.Valueparams = append(params,reflect.ValueOf(10))params = append(params,reflect.ValueOf(20))result := val.Method(0).Call(params)fmt.Println("AGetSum方法的返回值为:",result[0].Int())
}func main(){//定义结构体具体的实例:s := Student{Name : "丽丽",Age : 18,}//调用TestStudentStruct反射:TestStudentStruct(s)
}

修改结构体属性的值:

package main
import("fmt""reflect"
)//定义函数操作结构体进行反射操作:
func TestStudentStruct(a interface{}){//a转成reflect.Value类型:val := reflect.ValueOf(a)fmt.Println(val)n := val.Elem().NumField()fmt.Println(n)//修改字段的值:val.Elem().Field(0).SetString("张三")		注意点2
}func main(){//定义结构体具体的实例:s := Student{Name : "丽丽",Age : 18,}//调用TestStudentStruct:TestStudentStruct(&s)		注意点1fmt.Println(s)
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Node.js基本命令

以下是一些常用的Node.js命令&#xff1a; Node.js基本命令 node&#xff1a;用于运行一个Node.js脚本文件。例如&#xff1a;node app.js。node -v&#xff1a;查看已安装的Node.js版本。 npm命令 npm是Node.js的包管理工具&#xff0c;用于安装、升级、卸载和管理Node.js…

【二叉树】Leetcode 124. 二叉树中的最大路径和【困难】

二叉树中的最大路径和 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点&#xff0c;且不一定经过根节点。 路径和 是路径中各节点值的总和。 给你一个二叉树的根…

机器学习的特征选择方法

有时候特征太多了也是一个问题&#xff0c;容易过拟合。为了降低模型的复杂程度&#xff0c;降低过拟合的可能性&#xff0c;我们会减少需要的学习的特征。 特征选择法主要有三种&#xff0c;分别是过滤法&#xff0c;包裹法和嵌入法。 1.过滤法 这种方法主要是基于统计检验…

【QT+QGIS跨平台编译】056:【pdal_json_schema+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、pdal_json_schema介绍二、pdal下载三、文件分析四、pro文件五、编译实践一、pdal_json_schema介绍 pdal_json_schema 是与 PDAL(Point Data Abstraction Library)相关的 JSON 模式文件。PDAL 是一个用于处理和分析点云数据的开源库。JSON 模式…

wpf Line

详细解释 <Canvas x:Name"canvas"><Line x:Name"flowLine" X1"20" Y1"40" X2"400" Y2"100" StrokeDashArray"2,1" Stroke"Green" StrokeThickness"8"/><Line X1&q…

安装gitlab笔记

安装vim编辑器 yum install vim -y安装ssh协议&#xff0c;在CentOs系统上安装所需的依赖:ssh&#xff0c;防火墙,postfix(用于邮件通知)wget&#xff0c;以下这些命令也会打开系统防火墙中的HTTP和SSH端口访问 yum install -y curl policycoreutils-python openssh-server设…

ISP代理和数据中心IP的不同

ISP代理和数据中心IP在网络应用中都扮演着重要的角色 【定义】 ISP代理是由互联网服务提供商&#xff08;ISP&#xff09;提供的代理服务器。ISP代理的IP地址由ISP分配&#xff0c;这使得用户可以获得一个合法且唯一的IP地址&#xff0c;该地址隐藏了用户的实际位置。而数据中…

AutoMQ 1.1.0-RC0 重磅更新:内核升级到 Apache Kafka 3.7.0

AutoMQ 在 2024.02 正式发布了基于 Apache Kafka 3.4.0 的云原生重构版本 1.0.0&#xff0c;AutoMQ 1.0.0 版本相比原版提供了 Serverless、自动负载均衡、秒级分区迁移和 All in 对象存储能力&#xff0c;让 Kafka 用户能充分利用云的弹性能力和廉价存储&#xff0c;实现十倍成…

Flutter混淆方案对应用性能的影响分析与优化

在移动应用开发中&#xff0c;保护应用代码安全至关重要。Flutter 提供了简单易用的混淆工具&#xff0c;帮助开发者在构建 release 版本应用时有效保护代码。本文将介绍如何在 Flutter 应用中使用混淆&#xff0c;并提供了相关的操作步骤和注意事项。 &#x1f4dd; 摘要 本…

mysq性能优化-my.cnf配置文件参数调整

MySQL 优化配置文件&#xff08;my.cnf 或 my.ini&#xff09;是调整 MySQL 服务器性能的重要手段之一。以下是一些常见的场景&#xff0c;可以通过调整配置文件参数值来优化 MySQL&#xff1a; 1. **提高并发处理能力**&#xff1a; - innodb_buffer_pool_size&#xff1a;增…

【C++】lambda 表达式 / 包装器 / bind 绑定

目录 一. lambda 表达式1. lambda 表达式的语法1. lambda 表达式的使用2. lambda 表达式的捕捉列表 二. 包装器三. bind 绑定 一. lambda 表达式 Lambda 表达式是 C11 标准引入的一种新特性, 它提供了一种方便的方式来定义匿名函数. lambda 表达式实际上是一个匿名的仿函数; …

信创工程师招聘需求分析

职责描述&#xff1a; 1.配合河南区域行业拓展经理&#xff0c;负责河南区域各重点行业嵌入式、信息化软硬件解决方案的设计、研究与推广工作&#xff0c;支持用户开展CPU选型工作。 2. 负责支持飞腾重点行业方向重点客户嵌入式、信息化相关项目的PoC和实施支持工作&#xff0c…

【FTP,EMail】

文章目录 FTPFTP&#xff1a;文件传输协议FTP: 控制连接与数据连接分开FTP命令、响应 EMail电子邮件&#xff08;EMail&#xff09;邮件服务器EMail: SMTP [RFC 2821]SMTP&#xff1a;总结 FTP FTP&#xff1a;文件传输协议 向远程主机上传输文件或从远程主机接收文件。客户/服…

使用tcpdump和wireshark进行服务器抓包分析

目录 前言 1.tcpdump简介 2.Wireshark简介 3.实际案例 4.代码示例 5.总结 前言 服务器抓包分析是一种非常常见和有效的网络故障排查和性能优化手段。通过捕获服务器上的网络流量&#xff0c;可以帮助我们深入了解服务器与其它设备之间的通信情况&#xff0c;发现问题并进…

创新学术之道:如何充分利用ChatGPT优化论文写作过程

ChatGPT无限次数:点击直达 创新学术之道&#xff1a;如何充分利用ChatGPT优化论文写作过程 随着人工智能技术的发展&#xff0c;ChatGPT作为一种高效的自然语言处理工具&#xff0c;在学术领域的应用也日渐普及。本文将介绍如何充分利用ChatGPT优化论文写作过程&#xff0c;提…

Java多线程实战-从零手搓一个简易线程池(三)线程工厂,核心线程与非核心线程逻辑实现

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️本系列源码仓库&#xff1a;多线程并发编程学习的多个代码片段(github) &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正…

Mac上怎么合并多张图片?

Mac上怎么合并多张图片&#xff1f;上班过的小伙伴都应该知道&#xff0c;合并拼接图片是一件非常重要且经常需要使用到的图片处理技术&#xff0c;将多张图片合并拼成一张之后能够展现出更多的图片内容。在Mac电脑上&#xff0c;合并多张图片是一项常见的任务&#xff0c;无论…

策略模式详解+代码案例

首先简单介绍策略模式 该模式定义了一系列算法&#xff0c;并将每个算法封装起来&#xff0c;使它们可以相互替换&#xff0c;且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式&#xff0c;它通过对算法进行封装&#xff0c;把使用算法的责任和算法的实现分割开…

notepad++ 快捷键使用

notepad 很好用 使用快捷键能提高效率 以下为我常用的快捷键 键位效果ctrl l删除高亮行ctrl d重复高亮行ctrl k注释选中行ctrl q取消注释选中行ctrl w关闭文本窗口ctrl tab向右切换窗口ctrl shift tab向左切换窗口ctrl 滚轮向滚动方向切换窗口ctrl shift 滚轮滚动选…

【教程】Kotlin语言学习笔记(六)——泛型

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【Kotlin语言学习】系列文章 第一章 《认识Kotlin》 第二章 《数据类型》 第三章 《数据容器》 第四章 《方法》 第五章 《L…