【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,一经查实,立即删除!

相关文章

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

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

【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 模式…

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

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

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

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

【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;发现问题并进…

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

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

Mac上怎么合并多张图片?

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

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

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

关系型数据库设计

目录 1.数据库设计的重要性及定义 1.1 数据库设计的重要性 1.1.1 失败的数据库设计造成的后果 1.1.2 优秀的数据库设计带来的好处 1.2 数据库设计的定义 2.数据库需求分析 2.1 需求分析的步骤 2.1.1 收集信息 2.1.2 标识实体 2.1.3 标识每个实体的详细信息 2.1…

【HTML】制作一个简单的动态SVG图形

目录 前言 开始 HTML部分 CSS部分 效果图 总结 前言 无需多言&#xff0c;本文将详细介绍一段HTML和CSS代码&#xff0c;该代码用于创建一个动态的SVG图形&#xff0c;具体内容如下&#xff1a; 开始 首先新建文件夹&#xff0c;创建两个文本文档&#xff0c;其中HTML的文…

【2023】kafka原生以及配合springboot的使用(Kafka-3)

&#x1f4bb;目录 前言 一、依赖二、原生使用kafka1、发送消息1.1、生产者同步发送消息1.2、生产者异步发送消息1.3、常用配置&#xff1a; 2、接收消息2.1、关于消费者的自动提交和手动提交2.2、长轮训poll消息2.3、消费者的健康状态检查2.4、指定分区和偏移量&#xff0c;时…

使用docker-tc对host容器进行限流

docker-tc是一个github开源项目&#xff0c;项目地址是https://github.com/lukaszlach/docker-tc。 运行docker-tc docker run -d \ --name docker-tc \ --network host \ --cap-add NET_ADMIN \ --restart always \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /var…

Transformer - model architecture

Transformer - model architecture flyfish Transformer总体架构可分为四个部分: 输⼊部分 输出部分 编码器部分 解码器部分 输入部分 输出部分 输⼊部分包含: 源嵌⼊层和位置编码 ⽬标嵌⼊层和位置编码 输出部分包含: 线性层 softmax处理器 左侧编码器部分和右侧解码器部…

微信小程序自定义弹窗组件

业务背景&#xff1a;弹窗有时字体较多&#xff0c;超过7个字&#xff0c;不适用wx.showToast. 组件代码 <view class"toast-box {{isShow? show:}}" animation"{{animationData}}"><view class"toast-content" ><view class&q…

Taro + vue3 小程序封装标题组件

分为没有跳转页面的title组件和 有跳转页面的title组件 我们可以把这个封装成一个组件 直接上代码 <template><div class"fixed-title-container"><div class"box"><div class"icon" v-if"isShow" click"…

【论文阅读】DETR 论文逐段精读

【论文阅读】DETR 论文逐段精读 文章目录 【论文阅读】DETR 论文逐段精读&#x1f4d6;DETR 论文精读【论文精读】&#x1f310;前言&#x1f4cb;摘要&#x1f4da;引言&#x1f9ec;相关工作&#x1f50d;方法&#x1f4a1;目标函数&#x1f4dc;模型结构⚙️代码 &#x1f4…

ubuntu-server部署hive-part4-部署hive

参照 https://blog.csdn.net/qq_41946216/article/details/134345137 操作系统版本&#xff1a;ubuntu-server-22.04.3 虚拟机&#xff1a;virtualbox7.0 部署hive 下载上传 下载地址 http://archive.apache.org/dist/hive/ apache-hive-3.1.3-bin.tar.gz 以root用户上传至…

多层PCB内部长啥样?

硬件工程师刚接触多层PCB的时候&#xff0c;很容易看晕。动辄十层八层的&#xff0c;线路像蜘蛛网一样。 画了几张多层PCB电路板内部结构图&#xff0c;用立体图形展示各种叠层结构的PCB图内部架构。 高密度互联板(HDI)的核心 在过孔 多层PCB的线路加工&#xff0c;和单层双…

Transformer - Positional Encoding 位置编码 代码实现

Transformer - Positional Encoding 位置编码 代码实现 flyfish import torch import torch.nn as nn import torch.nn.functional as F import os import mathclass PositionalEncoding(nn.Module):def __init__(self, d_model, dropout, max_len5000):super(PositionalEnco…