golang的反射探索

news/2024/4/16 2:08:49

1、golang中反射常用的场景
1》类型检查—通用类包或者函数的时候,在运行时可以动态的获取任意对象的类型信息
2》动态调用方法—运行时动态的选择使用哪个方法
3》结构体标签处理—结构体字段一般是通过tag来注解。运行时可以通过反射读取tag。常用于解析配置文件,处理json,映射tag到某个特定的键。
4》动态操作结构体字段—运行时动态填充数据或者从一些通用的数据结构中提取数据。
5》实现通用编程-比如通用的库

2、三大定律
1》将接口类型变量转换为反射对象
反射对象指的是:reflect.type-表示接口值的类型信息和reflect.value-表示接口值的具体值,两种类型。

var x float64 = 1.1
v := x.reflect.ValueOf(x)//或者是typeOf()
// v是x的反射对象

v.type() // 表示类型
v.kind() // 表示底层的实际类型

2》反射对象可以转换为接口类型

var x float64 = 3.4v := reflect.ValueOf(x) // v是x的反射对象y := v.Interface().(float64) // 结果是3.4

3》要修改反射对象的值,其值必须是可以被设置的。(地址是不能直接去修改对应值的)

vv := reflect.ValueOf(&x)
vv.Elem().Set(reflect.ValueOf(111.11))
fmt.Println(x)

3、反射的常用场景示例
结构体为例
1》获取变量和方法

var ss = Student {Username:"aa",Age:11,
}
typeS := reflect.TypeOf(ss)
numField := typeS.NumField()
for i:=0;i<numField;i++ {field := typeS.Field(i)fmt.Printf("变量名:%s, 变量是否可见:%s, 变量的tag是:%s\n",field.Name, field.Anonymous, field.Tag)}

/*
输出结果是:
变量名:Username, 变量是否可见:%!s(bool=false), 变量的tag是:json:userName
变量名:Age, 变量是否可见:%!s(bool=false), 变量的tag是:json:age
*/


```go
func (s Student) GetName() string {return s.GetName()
}
// 注意这里是指针
func (s *Student) GetAge() int {return s.GetAge()
}// 这里获取的时候也是指针
typeStudentPoint := reflect.TypeOf(&ss)methodPoint := typeStudentPoint.NumMethod()for i:=0;i<methodPoint;i++ {method := typeStudentPoint.Method(i)fmt.Printf("method name:%s, type:%s\n", method.Name, method.Type)}/**
输出结果是:
method name:GetAge, type:func(*main.Student) int
method name:GetName, type:func(*main.Student) string
*/如果上面在获取typeof的时候,传进去的不是指针。那么结果又是怎么样呢?
结果是这样的:
method name:GetName, type:func(main.Student) string所以最好传进去地址,才能最大程度的使用所有的方法。

2、获取函数信息

func (s *Student) Add(a, b int) int {return a+b
}var ss = &Student {Username:"aa",Age:11,
}
var ss = &Student {Username:"aa",Age:11,}typeadd := reflect.TypeOf(ss.Add)for i:=0;i<typeadd.NumIn();i++ {fmt.Printf("%s\n",typeadd.In(i).Kind())}for i:=0;i<typeadd.NumOut();i++ {fmt.Printf("%s\n",typeadd.Out( i).Kind())}

3、是否实现了接口

type People interface {Color() string
}type Child struct {
}func (c *Child) Color() string {return "this is a child"
}type Dog struct {
}peopleType := reflect.TypeOf((*People)(nil)).Elem()fmt.Println("people is interface?", peopleType.Kind() == reflect.Interface)noPointChildType := reflect.TypeOf(Child{})pointChildType := reflect.TypeOf(&Child{})noPointDogType := reflect.TypeOf(Dog{})pointDogType := reflect.TypeOf(&Dog{})fmt.Println("nopoint child 是否实现了people接口:\n", noPointChildType.Implements(peopleType))fmt.Println("point child 是否实现了people接口:\n", pointChildType.Implements(peopleType))fmt.Println("nopoint dog 是否实现了people接口:\n", noPointDogType.Implements(peopleType))fmt.Println("nopoint dog 是否实现了people接口:\n", pointDogType.Implements(peopleType))/**
输出结果如下:
people is interface? true
nopoint child 是否实现了people接口:false
point child 是否实现了people接口:true
nopoint dog 是否实现了people接口:false
nopoint dog 是否实现了people接口:false*/

4、value转type

s := Student{Username:"miss zhao",}sValueOf := reflect.ValueOf(&s)fmt.Println(sValueOf.Elem().FieldByName("Username"))sTypeOf := sValueOf.Type()fmt.Println(sTypeOf)/**
输出结果如下:
miss zhao
*main.Student
*/

5、指针和非指针互转

// 指针和非指针互转s := Student{Username:"miss zhao",}// 指针sValueOf := reflect.ValueOf(&s)// 非指针noPoint := sValueOf.Elem()//*main.Student main.Studentfmt.Println(sValueOf.Type(), noPoint.Type())//互转point := noPoint.Addr()//*main.Studentfmt.Println(point.Type())

6、获取原始类型

s := Student{Username:"miss zhao",}sValueOf := reflect.ValueOf(&s)noPoint := sValueOf.Elem()// 转换为原始类型s = noPoint.Interface().(Student)fmt.Println(s.Username)

7、空value值的判断

// 相当于anyvar i interface{}v := reflect.ValueOf(i)fmt.Println(v.Kind() == reflect.Invalid)// 判断是否nilvar ss *Student = nilv = reflect.ValueOf(ss)if v.IsValid(){fmt.Println(v.IsNil())}//只声明 所有的值都是零值var s Studentv = reflect.ValueOf(s)// 必须先判断isValidif v.IsValid() {fmt.Println(v.IsZero())}

8、调用方法

func (s *Student) Add(a, b int) int {return a+b
}// main函数里
s := Student{Username:"miss zhao",}// 注意:使用指针可以调用指针和非指针的方法ss := reflect.ValueOf(&s)methodByName := ss.MethodByName("Add")resultSlice := methodByName.Call([]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)})fmt.Println(resultSlice[0].Interface().(int))
/**
这里的输出结果如下:
3
*/

http://www.ppmy.cn/news/1365054.html

相关文章

project.config.json 文件内容错误] project.config.json: libVersion 字段需为 string, string

家人们&#xff0c;遇到了一个新的报错 于是从网上找了各种方法&#xff0c;有说把开发者工具关闭重启的&#xff0c;有说开发者工具下载重新下载的&#xff0c;有说开发者工具路径安装得在C盘的&#xff0c;均没有效果 解决方法&#xff1a; 1、运行项目&#xff0c;在开发者…

OSX逆向分析基础

文章目录 前言OSX基础工具方法动态调试附录参考链接 前言 如果你想真正成为软件高手&#xff0c;就得了解底层运作机制。逆向&#xff0c;不会让你成为扎克伯格或张一鸣&#xff0c;但或许能让你成为安全专家。 OSX基础 Mac OS X下二进制可执行文件的动态链接库是dylib文件。…

Flink Catalog

1.Flink侧创建 按照SQL的解析处理流程在Parse解析SQL以后&#xff0c;进入执行流程——executeInternal。   其中有个分支专门处理创建Catalog的SQL命令 } else if (operation instanceof CreateCatalogOperation) {return createCatalog((CreateCatalogOperation) operatio…

通过一个例子演示golang调用C语言动态链接库中的函数

本例提供了cgo调用C函数的示例&#xff0c;也演示了如何将C函数打印内容保存到golang的变量中 目录和源码 目录结构 adminhpc-1:~/go/my_stdout$ tree . ├── include │ ├── mylibrary.c │ └── mylibrary.h ├── lib └── main.go2 directories, 3 files a…

Android 框架设计模板

不同项目在使用该模板时多少会有出入&#xff0c;应以项目实际情况作为依据。 &#xff08;该文档可以 .md 格式存放于项目根目录&#xff0c;或编写到readme 中&#xff09; 项目描述 涉及如下方面 项目背景 &#xff08;可引用项目立项书&#xff09;项目需求 &#xff08…

【kubernetes】关于k8s集群的声明式管理资源

目录 一、声明式管理方法 二、资源配置清单管理 1、导出资源配置清单 2、修改资源配置清单并应用 2.1离线修改 2.2在线修改 三、通过资源配置清单创建资源对象 获取K8S资源配置清单文件模板&#xff1f; 关于配置清单常见的字段 方案一&#xff1a;手写yaml配置文件 …

QT C++实践|超详细数据库的连接和增删改查操作|附源码

0&#xff1a;前言 &#x1faa7; 什么情况需要数据库? 1 大规模的数据需要处理&#xff08;比如上千上万的数据量&#xff09;2 需要把数据信息存储起来&#xff0c;无论是本地还是服务上&#xff0c;而不是断电后数据信息就消失了。 如果不是上面的原因化&#xff0c;一般…

学习JAVA的第四天(基础)

目录 方法 方法的定义 方法的调用 参数 注意事项 方法的重载 练习 面向对象 类和对象 定义类的注意事项 封装 private关键字 this关键字 构造方法 标准的Javabean类 创建一个对象时&#xff0c;虚拟机做了什么&#xff1f; 方法 方法含义&#xff1a;方法是程序…

Node.js+vue校内二手物品交易系统tdv06-vscode前后端分离

二手物品交易系统采用B/S架构&#xff0c;数据库是MySQL。网站的搭建与开发采用了先进的nodejs进行编写&#xff0c;使用了vue框架。该系统从三个对象&#xff1a;由管理员和用户、店铺来对系统进行设计构建。主要功能包括&#xff1a;个人信息修改&#xff0c;对用户、店铺、二…

【面试题】在浏览器地址栏输入URL后会发生什么

1. 地址栏输入后的本地操作 当我们在浏览器的地址栏中&#xff0c;输入xxx内容后&#xff0c;浏览器的进程首先会判断输入的内容&#xff1a; 如果是普通的字符&#xff0c;那浏览器会使用默认的搜索引擎去对于输入的xxx生成URL。如若输入的是网址&#xff0c;那浏览器会拼接…

golang使用gorm操作mysql1

1.mysql连接配置 package daoimport ("fmt""gorm.io/driver/mysql""gorm.io/gorm""gorm.io/gorm/logger" )var DB *gorm.DB// 连接数据库&#xff0c;启动服务的时候&#xff0c;init方法就会执行 func init() {username : "roo…

binwalk安装记录和burpsuite安装记录

我的虚拟机环境是Ubuntu20.04 python有2.7的和3.8的 [[#binwalk|binwalk]] [[#binwalk#pip|pip]][[#binwalk#安装 sasquatch|安装 sasquatch]][[#binwalk#安装 jefferson|安装 jefferson]][[#binwalk#安装 ubi_reader|安装 ubi_reader]][[#binwalk#安装 yaffshiv|安装 yaffshi…

2.26作业

2.将信号灯集的函数二次封装 sem.c #include<myhead.h>union semun {int val; /* Value for SETVAL */struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */unsigned short *array; /* Array for GETALL, SETALL */struct seminfo *__buf;…

Eigen-Array数组类和系数式运算

Array数组类和系数式运算&#xff09; 一、概述二、数组类型三、访问数组中的值四、加减法五、乘法六、其他系数相关的操作七、数组和矩阵表达式之间转换 一、概述 Array类提供了通用数组&#xff0c;而Matrix类则用于线性代数。此外&#xff0c;Array类提供了一种简单的方法来…

Linux中死锁种类和解决方法

死锁&#xff1a; 第一种&#xff1a; 加了两次锁&#xff0c;导致还没解锁就想获得锁&#xff0c;一直阻塞&#xff1a; void*mythread(void *arg) {int n5000;int x;while(n--){pthread_mutex_lock(&mutex);pthread_mutex_lock(&mutex);xnumber;x;numberx;pthread…

如何选购油烟净化器?环保性能与个人需求的完美契合

我最近分析了餐饮市场的油烟净化器等产品报告&#xff0c;解决了餐饮业厨房油腻的难题&#xff0c;更加方便了在餐饮业和商业场所有需求的小伙伴们。 在选择油烟净化器时&#xff0c;环保性能与个人需求的完美契合至关重要。下面&#xff0c;让我们一起探讨如何选购适合自己的油…

初识Lombok

前言 最近读一些公司的业务代码&#xff0c;发现近几年的java项目工程中都使用了lombok&#xff0c;lombok是一个可以自动生成get,set、toString等模板类方法的工具框架&#xff0c;程序再引入lombok后&#xff0c;添加一个注解便可以不写get\set\toString等方法。 Lombok示例…

蓝桥杯Learning

Part 1 递归和递推 1. 简单斐波那契数列 n int(input())st [0]*(47) # 注意这个地方&#xff0c;需要将数组空间设置的大一些&#xff0c;否则会数组越界 st[1] 0 st[2] 1 # 这个方法相当于是递推&#xff0c;即先求解一个大问题的若干个小问题 def dfs(u):if u 1:print(…

未来新质生产力Agent的起源与应用

Agent是什么&#xff1f; AI Agent的发展经历了从哲学思想启蒙到计算机科学助力、专家系统兴起、机器学习崛起、深度学习突破等多个阶段。如今&#xff0c;AI Agent已经成为人工智能领域的重要组成部分&#xff0c;为人类带来了巨大的便利和发展机遇。早在古希腊时期&#xff0…

第十一天-Excel的操作

目录 1.xlrd-Excel的读模块 安装 使用 获取工作簿 读取工作簿的内容 xlsxwriter-Excel的写模块 安装 使用 生成图表 add_series参数 图表的样式 demo&#xff1a;生成图表 Excel的操作在python中有多个模块&#xff0c;为了能够快速使用&#xff0c;选择了相对简单…
最新文章