【Go】二十、反射

news2024/11/15 6:01:44

文章目录

  • 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 + 30
        fmt.Println(n2)
}


func main(){
        //对基本数据类型进行反射:
        //定义一个基本数据类型:
        var num int = 100
        testReflect(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 string
        Age 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 string
        Age 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 = 100
        testReflect(&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 string
        Age 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 = name
        s.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.Value
        params = 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)		注意点1
        fmt.Println(s)
}

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

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

相关文章

用苹果CMS一小时搭建自己的私人影院(仅供学习与参考,请勿用于商业用途)

用苹果CMS一小时搭建自己的私人影院&#xff08;仅供学习与参考&#xff0c;请勿用于商业用途&#xff09; 一、购买域名和服务器空间或虚拟主机空间。 二、下载苹果CMS影视安装程序到本地。 三、上传苹果CMS安装程序至你的空间并安装。 四、后台设置完善你的电影网站。 五、…

缓存击穿以及解决方案

1.定义 缓存击穿问题也叫热点Key问题&#xff0c;就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了&#xff0c;无数的请求访问会在瞬间给数据库带来巨大的冲击。 问题描述&#xff1a;假设线程1在查询缓存之后&#xff0c;本来应该去查询数据库&#xff0c;然后把…

信息收集之内网渗透(二)

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 0、前言 本文主要是一些命令的集合&#xff0c;会比较枯…

鸿蒙南向开发实战:【智能扫地机】

样例简介 ​ 此Demo采用润和的智能小车套件为硬件模型&#xff0c;通过修改代码具备了扫地机器人简易的避障功能及防跌落功能&#xff0c;并且能通过wifi接入数字管家应用场景。智能扫地机不仅能接收数字管家应用下发的指令启动或停止扫地机器人&#xff0c;而且还可以加入到数…

定时器测试:用定时器监控定时器

using System; using System.Timers;namespace TestTimer {internal class Program{private static int usingResource 0;static int m 0;static Timer timerTask new Timer();static Timer timerMonitor new Timer();static void Main(string[] args){//任务 定时器timerT…

大模型系列——解读RAG

上篇大概说了几个优化方向&#xff0c;包括提示词&#xff0c;RAG等。那么RAG到底是什么呢&#xff1f;RAG 是2023年最流行的基于 LLM 的应用系统架构。有许多产品几乎完全建立在 RAG 之上&#xff0c;覆盖了结合网络搜索引擎和 LLM 的问答服务&#xff0c;到成千上万个数据聊天…

JSP课设:学校招生系统(附源码+调试)

Java web学校招生系统 Java web学校招生系统功能概述 &#xff08;1&#xff09;登录模块&#xff1a;学校招生系统提供管理员和考生两者登录角色&#xff0c;分别对应不同的功能&#xff0c;登录信息存储在数据库中。 &#xff08;2&#xff09;前台浏览&#xff1a;学校招生…

让智能体像Excel易用还要多久?

2023年&#xff0c;国内AI产业迎来狂飙时代。大模型热潮推动AI智能体&#xff08;AI Agent&#xff09;发展&#xff0c;继ChatGPT成功后&#xff0c;OpenAI目标直指AI Agents。上半年&#xff0c;行业竞相扩大模型规模、提升参数和计算能力&#xff0c;抢占AI浪潮先机。然而&a…

【Easy云盘 | 第二篇】后端统一设计思想

文章目录 4.1后端统一设计思想4.1.1后端统一返回格式对象4.1.2后端统一响应状态码4.1.3后端统一异常处理类4.1.4StringUtils类4.1.5 RedisUtils类 4.1后端统一设计思想 4.1.1后端统一返回格式对象 com.easypan.entity.vo.ResponseVO Data public class ResponseVO<T> …

AFCI 应用笔记三、使用 mlflow 管理模型

1. 简介 由于 AI 神经网络涉及多种参数&#xff0c;需要频繁修改各种超参数&#xff0c;比如&#xff1a;learning rate&#xff0c;batchsize&#xff0c;filter numbers&#xff0c;alpha 等等&#xff0c;每个参数都有可能影响到模型最终的准确率&#xff0c;所以比较这些参…

C语言——顺序表

文章目录 一、线性表二、顺序表顺序表和数组的区别顺序表的分类1.静态顺序表2.动态顺序表 三、动态顺序表的实现1.动态顺序表头文件2.动态顺序表源文件3.测试源文件 一、线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。线性表是⼀种…

软考——数据库系统工程师

时间周期 流水线 IO功能 基本出现的选项中是必考而且基本都是全选 系统总线 后缀表达式 必考2分 答案&#xff1a;B 、 A 用栈来进行计算的。 第一个题先进行36-34的运算&#xff0c;所以是数字后面的第一个符号是减号呀&#xff01;&#xff01;&#xff01; 很重要的知识点…

C语言整数和小数的存储

1.整数在内存中的存储 计算机使用二进制进行存储、运算&#xff0c;整数在内存中存储使用的是二进制补码 1.1原码、反码、补码 整数的2进制表⽰⽅法有三种&#xff0c;即 原码、反码和补码 三种表⽰⽅法均有符号位和数值位两部分&#xff0c;符号位都是⽤0表⽰“正”&am…

27.WEB渗透测试-数据传输与加解密(1)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;26.WEB渗透测试-BurpSuite&#xff08;五&#xff09; BP抓包网站网址&#xff1a;http:…

二分答案 蓝桥杯 2022 省A 青蛙过河

有些地方需要解释&#xff1a; 1.从学校到家和从家到学校&#xff0c;跳跃都是一样的&#xff0c;直接看作2*x次过河就可以。 2.对于一个跳跃能力 y&#xff0c;青蛙能跳过河 2x 次&#xff0c;当且仅当对于每个长度为 y 的区间&#xff0c;这个区间内 h 的和都大于等于…

卷积神经网络-批量归一化

卷积神经网络-批量归一化 批量归一化的原理批量归一化的优点批量归一化的应用批量归一化的实现TensorFlow实现&#xff1a;PyTorch实现&#xff1a; 总结 批量归一化&#xff08;Batch Normalization&#xff0c;简称BN&#xff09;是一种用于提高深度神经网络训练速度和稳定性…

隐私计算实训营第七讲-隐语SCQL的开发实践

隐私计算实训营第七讲-隐语SCQL的开发实践 文章目录 隐私计算实训营第七讲-隐语SCQL的开发实践1.如何使用SCQL&#xff1f;2.使用流程3.SCQL部署4.SCQL使用示例4.1创建用户4.2创建项目&用户授权4.3创建表4.4设置CCL4.5发起联合分析查询 1.如何使用SCQL&#xff1f; 2.使用流…

Mysql的物理文件

1.Windows下面的配置文件是&#xff1a;my.ini [mysql] default-character-setutf8[mysqld] port3306 default_authentication_pluginmysql_native_password basedirE:/phpStudy/phpstudy_pro/Extensions/MySQL8.0.12/ datadirE:/phpStudy/phpstudy_pro/Extensions/MySQL8.0.1…

【刷题】代码随想录算法训练营第二天| 977. 有序数组的平方、209.长度最小的子数组、59.螺旋矩阵II

目录 977、有序数组的平方双指针法 209、长度最小的子数组滑动窗口 59、螺旋矩阵II 977、有序数组的平方 文档讲解&#xff1a;https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html 视频讲解&#xff1a;https://…

揭秘AI幻觉:GPT-4V存在视觉编码漏洞,清华联合NUS提出LLaVA-UHD

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 GPT-4V 的推出引爆了多模态大模型的研究。GPT-4V 在包括多模态问答、推理、交互在内的多个领…