go学习之反射知识

反射

文章目录

    • 反射
      • 1、反射的使用场景
        • 1)结构体标签的应用
        • 2)使用反射机制编写函数的适配器(桥连接)
      • 2、反射的基本介绍
        • -1.基本介绍
        • -2.反射的图解
        • -3.反射重要的函数和概念
      • 3.反射快速入门
        • -1.请编写一个函数,演示对(基本数据类型、interface{}、reflect.Value)进行反射的基本操作。
        • -2.请编写一个案例,演示对(结构体类型、interface{}、reflect.Value)进行反射的基本操作
      • 4.反射的注意事项和细节说明
        • 1)reflect.Value.Kind,获取变量的类别,返回的是一个常量
        • 2)Type是类型,kind是类别,Type和Kind可能是相同的,也可能是不同的
      • 5.反射练习题
      • 6.反射的最佳实践

1、反射的使用场景

1)结构体标签的应用

在这里插入图片描述

2)使用反射机制编写函数的适配器(桥连接)

在这里插入图片描述

2、反射的基本介绍

-1.基本介绍

1)反射可以在运行时动态获取变量的各种信息,比如变量的类型(type),类别(kind)

2)如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)

3)通过反射,可以修改变量的值,可以调用关联的方法

4)使用反射,需要import (“reflect”)

-2.反射的图解

在这里插入图片描述

-3.反射重要的函数和概念

1)reflect.TypeOf(变量名)。获取变量的类型,返回reflect.Type类型

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

3)变量、interface{}和reflect.Value是可以相互转换的,这点在实际开发中,会经常使用到。

3.反射快速入门

-1.请编写一个函数,演示对(基本数据类型、interface{}、reflect.Value)进行反射的基本操作。

代码演示

package mainimport ("fmt""reflect")//专门反射演示func reflectTest01(b interface{}) {//通过反射获取的传入的变量 type,kind,值//1.先获取到reflect.TyperTyp :=reflect.TypeOf(b)fmt.Println("rTyp=",rTyp) //int//2.获取到reflectValuerVal :=reflect.ValueOf(b) //100// n1 := 10// n2 := 2 + rVal// fmt.Println("n2=",n2)//erro // n1 := 10n2 := 2 + rVal.Int()fmt.Println("n2=",n2) //102fmt.Printf("rVal=%v type=%T\n",rVal,rVal) //rVal=100 type=reflect.Value//下面我们将rVal转成interface{}iv := rVal.Interface()//将interface{}通过断言转成需要的类型num2 := iv.(int)fmt.Println("num2=",num2) //num2= 100}func main() {//-1.请编写一个函数,演示对(基本数据类型、interface{}、reflect.Value)进行反射的基本操作。//1、先定义一个intvar num int = 100reflectTest01(num)}
-2.请编写一个案例,演示对(结构体类型、interface{}、reflect.Value)进行反射的基本操作
 //专门演示对结构体的反射func reflectTest02(b interface{}) {//通过反射获取的传入的变量 type,kind,值//1.先获取到reflect.TyperTyp :=reflect.TypeOf(b)fmt.Println("rTyp=",rTyp) //rTyp= main.Student//2.获取到reflectValuerVal :=reflect.ValueOf(b)//下面我们将rVal转成interface{}iv := rVal.Interface()fmt.Printf("iv=%v ,iv type=%T\n",iv,iv) //iv={Tom 20} ,iv type=main.Student//将interface{}通过断言转成需要的类型// fmt.Printf("iv=%v ,iv type=%T name\n",iv,iv,iv.Name) //erro无法取出name的值//所以先要进行断言stu,ok :=iv.(Student)if ok {fmt.Printf("stu.Name=%v\n",stu.Name)//stu.Name=Tom}}type Student struct {Name stringAge int}func main() {//2.定义一个Student的实例stu := Student{Name : "Tom",Age : 20,}reflectTest02(stu)}

4.反射的注意事项和细节说明

1)reflect.Value.Kind,获取变量的类别,返回的是一个常量

补充常量是知识

常量介绍

  • 常量使用const修改

  • 常量在定义的时候,必须初始化

  • 常量不能修改

  • 常量只能修饰bool、数值类型(int,float系列)、string类型

    语法: const identifier [type] = value

    package main
    import ("fmt"
    )
    func main() {var num intnum = 90 //常量声明的时候必须赋值const tax int = 90// tax = 10 //常量是不能修改的fmt.Println(num,tax)//常量只能修饰bool、数值类型(int,float系列)、string类型//const b =num /3 erro
    }
    

    常量使用注意事项

    1》比较简洁的写法

    func main () {
    const(a = 1b = 2
    )
    }
    

    2》还有一种专业的写法

    func main(){const(a = iotabc)fmt.Println(a,b,c)//0,1,2
    }
    

    3》Golang中没有常量名必须大写的规范

    4》仍然通过首字母的大小来控制常量的访问范围

2)Type是类型,kind是类别,Type和Kind可能是相同的,也可能是不同的

比如: var num int = 10 num 的Type是int, Kind也是int

比如:var stu Student stu 的Type是包名.Student,Kind是struct(Kind的等级 >Type的等级)

3)通过反射可以让变量在interface{}和Reflect.Value之间相互转换

4)使用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,比如x是int,那么就应该使用reflect.Value(x)Int(),而不能使用其他的,否则报panic

5)通过反射的值来修改变量。注意当使用SetXxx方法来设置需要通过对应的指针类型来完成,这样才能改变传入的值,同时需要使用到reflect.Value.Elem()方法

package main
import ("fmt""reflect"
)//通过反射,修改
//num int 的值
//修改student的值func reflect01(b interface{}){//获取到reflect.ValuerVal := reflect.ValueOf(b)rVal.Elem().SetInt(20)
}
func main() {var num int = 10reflect01(&num)fmt.Println("num=",num) //20//你可以这样理解这句话:rVal.Elem()// num := 9//  ptr *int = &num//  num2 :=*ptr
}

6)如何理解rVal.Elem()

//你可以这样理解这句话:rVal.Elem()// num := 9//  ptr *int = &num//  num2 :=*ptr
}

5.反射练习题

1)给你一个变量 var v float64 = 1.2.请使用反射来得到它的reflect.Value,然后获取对应的Type,Kind和值,并将reflect.Value转换成interface{}.,再将interface{}转换成float64

package mainimport ("fmt""reflect")func reflect01(b interface{})  {num := reflect.ValueOf(b)kind1 :=num.Kind()iv :=num.Interface()fmt.Printf("b的reflect.Value是=%v,kind值为=%v,num转换为interface的值为=%v",num,kind1,iv)}func main() {var n float64 =65.9reflect01(n)}

2)给字符串改名题

        var str string = "tom"fs :=reflect.ValueOf(&str) //这里要改成地址fs.Elem().SetString("jackma")fmt.Println(str)

6.反射的最佳实践

1)使用反射来遍历结构体的字段,调用结构体的方法,并获取结构体标签的值
2)使用反射的方式来获取结构体的tag标签,遍历字段的值,修改字段值,调用结构体方法
val.Method(0).Call() 调用第一个方法
方法的排序默认是按照函数名的排序(ASCII码)
定义了两个函数testl 和test2, 定义一个适配器函数用作统一 处理接口
使用反射操作任意结构体类型
使用反射创建并操作结构体

package main
import ("fmt""reflect"
)//定义了一个Monster结构体
type Monster struct{Name string `json:"name"`Age int `json:"age"`Score float32 `json:"成绩"`Sex string
}// 方法: 返回两数之和
func(s Monster) GetSum(n1, n2 int) int{return n1 + n2
}// 方法: 接收四个值, 给S赋值
func(s Monster) Set(name string, age int, score float32, sex string){s.Name = names.Age = ages.Score = scores.Sex = sex
}//方法,显示s的值
func (s Monster) Print() {fmt.Println("--start--")fmt.Println(s)fmt.Println("--end--")
}func TestStruct(a interface{}){//获取reflect.Type类型typ := reflect.TypeOf(a)//获取reflect.Value类型val := reflect.ValueOf(a)//获取到a对应的类别kd := val.Kind()//如果传入的不是struct,就退出if kd != reflect.Struct {fmt.Println("Expect struct")return}//获取到该结构体有几个字段num := val.NumField()fmt.Printf("struct has %d fields\n", num) //4//变量结构体的所有字段for i := 0; i < num; i++ {fmt.Printf("Field %d:值为=%v\n", i, val.Field(i))//获取到struct 标签,注意需要通过reflect.Type来获取tag标签的值tagVal := typ.Field(i).Tag.Get("json")//如果该字段于tag标签就显示,否则就不显示if tagVal != "" {fmt.Printf("Field %d: tag为=%v\n", i, tagVal)}}//获取到该结构体有多少个方法numOfMethod := val.NumMethod()fmt.Printf("struct has %d methods\n", numOfMethod)//var params []reflect.Value//方法的排序默认是按照函数名的排序(ASCII码)val.Method(1).Call(nil)//获取到第二个方法。调用它//调用结构体的第1个方法Method(0)var params []reflect.Value //声明了[]reflect.Valueparams = append(params, reflect.ValueOf(10))params = append(params, reflect.ValueOf(40))res := val.Method(0).Call(params) //传入的参数是[]reflect.Value,返回[]reflect.Valuefmt.Println("res=", res[0].Int()) //返回结果,返回的结果是[]reflect.Value*/
}func main(){var a Monster = Monster{Name: "黄鼠狼精",Age: 400,Score: 30.8,} //将Monster实例传递给TestStruct函数TestStruct(a)
}

2)使用反射操作任意结构体类型

type user struct {UserId stringName string}func TestReflectStruct(t *testing.T){var {model *usersv reflect.Value}model = &user{}sv = reflect.ValueOf(model)t.Log("reflect.ValueOf",sv.kind().String())sv=sv.Elem()t.Log("reflect.ValueOf",,sv.kind().String())sv.FieldByName("userId").SetString("12345678")sv.FieldByName("Name").SetString("nickname")t.Log("model",model)}

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

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

相关文章

【C进阶】C程序是怎么运作的呢?-- 程序环境和预处理(下)

前言&#xff1a; 这是程序环境和预处理的下半篇文章。至此&#xff0c;关于c语言知识点:从编译到运行的过程已讲解完毕。传送&#x1f6aa;&#xff0c;上半篇&#xff1a; http://t.csdnimg.cn/hvxmr 本章涉及的知识点&#xff1a; 宏和函数对比、命名约定、#undef、命令行定…

C语言—每日选择题—Day46

第一题 1. 下列程序段的输出结果是&#xff08;&#xff09; #include <stdio.h> int main() {int x 1,a 0,b 0;switch(x) {case 0: b;case 1: a;case 2: a;b;}printf("a%d,b%d\n", a, b);return 0; } A&#xff1a;a2,b1 B&#xff1a;a1,b1 C&#xf…

JVM面试

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.JVM 的整体结构2.类加载做了哪些事情?类加载器有哪些&#xff1f;双亲委派和沙箱安全 3.Java虚拟机栈是什么4.方法区的理解HotSpot 中方法区的演进方法区的内部结…

【Spring教程26】Spring框架实战:从零开始学习SpringMVC 之 bean加载控制

目录 1 问题分析2 思路分析3 环境准备4 设置bean加载控制5 知识点1&#xff1a;ComponentScan 欢迎大家回到《Java教程之Spring30天快速入门》&#xff0c;本教程所有示例均基于Maven实现&#xff0c;如果您对Maven还很陌生&#xff0c;请移步本人的博文《如何在windows11下安装…

文件搜索项目演示

演示功能搜索功能1&#xff1a;根据文件名搜索2&#xff1a;根据文件路径搜索3&#xff1a;根据文件名拼音(全拼、首拼)搜索 选择更新目录功能自动初始化和定时更新功能程序文件项目知识介绍 演示功能 搜索功能 1&#xff1a;根据文件名搜索 2&#xff1a;根据文件路径搜索 3…

Linux--操作系统

1. 常见的操作系统 Windowsmac OSLinuxiOSAndroid 2. 操作系统的定义 操作系统直接运行在计算机上的系统软件&#xff0c; 它是控制硬件和支持软件运行的计算机程序。 3. 操作系统的作用 向下控制硬件向上支持软件的运行&#xff0c;具有承上启下的作用。 4.总结 操作系统…

Win10的SVN Adapter V1.0 中黄色感叹号 -- 解决

大部分都问题都可以通过&#xff1a; 关闭 SVN Adapter V1.0 在下载最新的 SVNDrv.sys替换 C:\Windows\System32\drivers 中的同名文件启动 SVN Adapter V1.0 就能成功 但是部分人的电脑 SVN Adapter V1.0 是有感叹号的&#xff0c;说明注册表有问题 先用 CCleaner 修复注册表…

vue实现移动端适配

目录 1. 使用vw单位&#xff1a;vw是视窗宽度的百分比&#xff0c;可以根据不同设备的屏幕宽度来进行自适应。在Vue中可以通过设置全局CSS样式&#xff0c;将所有的尺寸单位改为vw。 2. 使用Flexible.js&#xff1a;Flexible.js是一个用于淘宝移动端适配的库&#xff0c;可以…

正则表达式(8):基本正则表达式小结

正则表达式&#xff08;8&#xff09;&#xff1a;基本正则表达式小结 本博文转载自 写这篇文章的目的就是总结前文中所介绍的”基本正则表达式”&#xff0c;并且结合一些实例进行练习&#xff0c;以便我们能够在练习中完全掌握它们。 首先&#xff0c;我们对前文中提到的符…

【rabbitMQ】声明队列和交换机

上一篇&#xff1a;springboot整合rabbitMQ模拟简单收发消息 https://blog.csdn.net/m0_67930426/article/details/134904766?spm1001.2014.3001.5501 相关配置环境参考上篇 springAMQP提供了几个类用来声明声明队列&#xff0c;交换机及其绑定关系 声明队列&#xff0c;…

Rational rose 安装教程(图文)

Rational Rose是Rational公司出品的一种面向对象的统一建模语言的可视化建模工具。用于可视化建模和公司级水平软件应用的组件构造。 就像一个戏剧导演设计一个剧本一样&#xff0c;一个软件设计师使用Rational Rose&#xff0c;以演员&#xff08;数字&#xff09;、使用拖放式…

第三届iEnglish全国ETP大赛16强落位 诠释教育游戏价值

10日,与北方骤降的温度形成鲜明对比,以“玩转英语,用iEnglish”为主题的国内首个教育游戏活动第三届iEnglish全国ETP(English Through Pictures)大赛总决赛小组赛热火朝天的进行。随着“云帆沧海队”搭上末班车,本届活动16强全部产生,接下来的三个周末他们将向年度总冠军发起最…

C# WPF上位机开发(增强版绘图软件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们写过一个绘图软件&#xff0c;不过那个比较简单&#xff0c;主要就是用鼠标模拟pen进行绘图。实际应用中&#xff0c;另外一种使用比较多的…

Leetcode—509.斐波那契数【简单】

2023每日刷题&#xff08;五十七&#xff09; Leetcode—509.斐波那契数 实现代码 int fib(int n){if(n 0) {return 0;}if(n 1) {return 1;}return fib(n-1) fib(n-2); }运行结果 之后我会持续更新&#xff0c;如果喜欢我的文章&#xff0c;请记得一键三连哦&#xff0c;点…

网络安全公司梳理,看F5如何实现安全基因扩增

应用无处不在的当下&#xff0c;从传统应用到现代应用再到边缘、多云、多中心的安全防护&#xff0c;安全已成为企业数字化转型中的首要挑战。根据IDC2023年《全球网络安全支出指南》&#xff0c;2022年度中国网络安全支出规模137.6亿美元&#xff0c;增速位列全球第一。有专家…

磁力计LIS2MDL开发(1)----轮询获取磁力计数据

磁力计LIS2MDL开发.1--轮询获取磁力计数据 概述视频教学样品申请源码下载通信模式速率生成STM32CUBEMX串口配置IIC配置CS设置串口重定向参考程序初始换管脚获取ID复位操作BDU设置设置速率启用偏移消除开启温度补偿设置为连续模式轮询读取数据主程序演示 概述 本文将介绍如何使…

Knowledge Graph知识图谱—9. Data Quality and Linking

9. Data Quality and Linking 9.1 How well are the linked open data in practice? Linked Open Vocabularies(LOV) project – analyze usage of vocabularies 9.2 Quality Linked Data Conformance vs. Quality Conformance: – i.e., following standards and best prac…

【git push ERROR: commit id: missing Change-Id in message footer】

使用 gerrit 后&#xff0c;提交代码会出现如下截图问题&#xff1a; 临时解决&#xff1a; step1: 把上面红色的那条gitidir复制下来执行下&#xff1a; step2:执行下面的命令会添加change_id git commit --amendstep3: 然后推送代码到服务器上 git push origin HEAD:refs/fo…

事件驱动架构 vs. RESTful架构:通信模式对比与选择

1. 通信风格 事件驱动架构&#xff08;EDA&#xff09; 是一种异步通信风格&#xff0c;组件之间通过产生和消费事件进行通信。 事件是表示系统中重大变化或事件的消息&#xff0c;并分发给感兴趣的组件。这种通信模型允许系统的不同部分之间进行解耦和动态交互。 组件充当事件…

新手上路:盘点「性能测试」必须掌握的技术点

前段时间&#xff0c;有一些小伙伴提出希望我们推送点性能测试的技术干货。所以&#xff0c;小编今天通过上网查资料&#xff0c;结合项目实操过程中的一些问题&#xff0c;总结了一些关于性能测试的内容&#xff0c;希望是大家想要了解的内容哈。 1、性能测试的目的 首先&am…