day15反射

news/2024/7/5 5:35:00/文章来源:https://www.cnblogs.com/dengz/p/18280827

了解go的反射

  • 反射:与 面向对象中的反射类似!
    • 程序运行中,获取到的信息(变量:类型,值。 结构体:字段,方法)
    • 可以通过反射机制,来改变变量和值
    • reflect 包, 实现反射
    • reflect.Type : 类型。 指示某一种类型
    • reflect.Value : 值
    • reflect.Kind : 种类。用于反射场景更多,指代的是相似的一些类型,当遇到自定义类型时,使用kind获取原始种类
  • 为什么使用反射
    • 编写函数时,不知道函数传递的参数是什么类型。使用any接收一切参数,利用反射 reflect 识别数据类型,种类
    • 用户输入数据类型不清楚时,利用反射获取数据类型,种类。 程序运行期间动态处理

静态类型和动态类型

  • 在反射过程中。程序编译的时候变量类型为静态类型,程序运行过程中变量是动态类型。
  • 静态类型:
    • var name string // 静态类型
  • 动态类型:
    • var A interface {} // 静态类型
    • A = 10 // interface 静态类型, 运行时属于动态类型 int
    • A = "abcd" // interface 静态类型, 运行时属于动态类型 string

反射使用

  • 通过反射获取信息
package mainimport ("fmt""reflect"
)type AType int
type User struct {name   stringage    intsex    boolcustom AType
}// 必须是暴露出来的方法,小写的私有方法不被查看到
func (u User) Say(content string) {fmt.Printf("用户:%s 。 说:%s\n", u.name, content)
}
func (u User) GetInfo() {fmt.Printf("用户名:%s,用户年龄:%d,用户性别:%d", u.name, u.age, u.sex)
}
func analyticDataFunc(v interface{}) {// v 是一个任意变量// 1. 获取 v 的类型。 一般使用Kind,Type会被用户自定getType := reflect.TypeOf(v) // Type 类型fmt.Println("v type:", getType)// 1.1 . 通过vType 获取 v 的 名称vName := getType.Name()fmt.Println("v name:", vName)// 1.2 . 通过 vType 获取 Kind 的种类vKind := getType.Kind()fmt.Println("v kind:", vKind)// 2. 获取 v 变量中的值getValue := reflect.ValueOf(v)fmt.Println("v value:", getValue)// 2.1 遍历字段 和 具体的值:// getValue.NumField() 获取字段和值,该函数返回长度。非可遍历for index := 0; index < getValue.NumField(); index++ {vFieldName := getType.Field(index)    // 字段信息vFieldValue1 := getValue.Field(index) // 值fmt.Println("v变量包含的信息:", "字段:", vFieldName, "值:", vFieldValue1)}// 2.2 遍历方法// getType.NumMethod() 获取 大写开头的 暴露的出来的函数数量!for i := 0; i < getType.NumMethod(); i++ {method := getType.Method(i)fmt.Printf("method Name:【%s】 method Type:【%v】\n", method.Name, method.Type)}}
func main() {/*反射场景- 通过反射获取信息*/var u = User{"张三", 3, true, 1000000}fmt.Println("define u data:", u)u.Say("你好")u.GetInfo()analyticDataFunc(u)
}

通过反射修改数据

  • 通过反射修改值,需要操作对象的指针,拿到地址
package mainimport ("fmt""reflect"
)func main() {/* 通过反射修改信息 */// 通过反射修改值,需要操作对象的指针,拿到地址var num = 3.14pointer := reflect.ValueOf(&num)newValue := pointer.Elem()            // 获取指针对象fmt.Println("类型:", newValue.Type()) // 使用 Kind()fmt.Println("判断该类型能否修改:", newValue.CanSet())newValue.SetFloat(2.11) // 通过反射修改数据fmt.Println("newValue:", newValue)}

通过反射修改变量的函数

package mainimport ("fmt""reflect"
)func reflectionModifiedVariableFunc(v any) reflect.Value {// 通过反射修改变量pointer := reflect.ValueOf(v) // 操作地址对象newValue := pointer.Elem()newValueType := newValue.Kind()fmt.Println("        [待修改变量] 值:", newValue)fmt.Println("        [待修改变量] 原类型:", newValueType)fmt.Println("        [待修改变量] 是否能修改:", newValue.CanSet())if newValueType == reflect.Int {newValue.SetInt(100)}if newValueType == reflect.String {newValue.SetString("李四")}return newValue
}func main() {var modifyVal1 = 1var modifyVal2 = "你好"fmt.Println("【修改前】", modifyVal1, modifyVal2)res1 := reflectionModifiedVariableFunc(&modifyVal1)res2 := reflectionModifiedVariableFunc(&modifyVal2)fmt.Println("【修改后】", res1, res2)}

通过反射修改结构体

package mainimport ("fmt""reflect"
)type Student struct {Name stringage  intAge  int
}func main() {/* 通过反射修改结构体变量数据 */var stu = Student{"张三", 19, 20}fmt.Println("stu:", stu)stuStructValue := reflect.ValueOf(&stu)if stuStructValue.Kind() == reflect.Ptr {// 获取指针对象newValue := stuStructValue.Elem()if newValue.CanSet() {// 找到要修改结构体的字段// 反射:字段必须大写开头 , 小写触发恐慌 panicnewValue.FieldByName("Name").SetString("lisi")newValue.FieldByName("Age").SetInt(333)}}fmt.Println("反射修改后的stu:", stu)}

反射调用结构体方法

  • MethodByName 找到函数名。必须大写
  • Call 执行 函数。
    • 无参数 传入 nil
    • 有参数,传入Value类型
package mainimport ("fmt""reflect"
)type StudentA struct {Name stringAge  int
}func (s StudentA) Say(content string) {/* 传入结构体方法 有参数*/fmt.Println(s.Name, "Say:【", content, "】")
}
func (s StudentA) GetInfo() {/* 传入结构体方法  无参数*/fmt.Printf("name: %s, age: %d\n", s.Name, s.Age)
}func main() {/*通过 反射修 调用方法- 1. MethodByName 找到函数名。必须大写- 2. Call 执行 函数。- 2.1 无参数 传入 nil- 2.2 有参数,传入Value类型*/var stu = StudentA{"张三", 20}fmt.Println("stu:", stu)stuStructValue := reflect.ValueOf(&stu)fmt.Printf("stuStructValue Kind:%s, Type:%s\n", stuStructValue.Kind(), stuStructValue.Type())if stuStructValue.Kind() == reflect.Ptr {// 获取指针对象newValue := stuStructValue.Elem()fmt.Printf("newValue Kind:%s, Type:%s\n", newValue.Kind(), newValue.Type())// 无参函数,通过反射调用 . 传入 nilnewValue.MethodByName("GetInfo").Call(nil)// 有参函数,通过反射调用。 传入 []Valueargs := make([]reflect.Value, 1)          // make 定义参数类型args[0] = reflect.ValueOf("这是反射调用") // 必须传入 Value类型的参数 。张三 Say:【 这是反射调用 】newValue.MethodByName("Say").Call(args)}}

反射调用普通函数

package mainimport ("fmt""reflect"
)func f1() {fmt.Println("无参函数")
}
func f2(i string) {fmt.Println("有参函数:", i)}
func f3(i, s string) string {fmt.Println("有参函数,有返回值:", i, s)return s
}
func main() {/*反射调用函数*/// 无参v1 := reflect.ValueOf(f1)fmt.Println(v1.Kind(), v1.Type())v1.Call(nil)// 有参v2 := reflect.ValueOf(f2)fmt.Println(v2.Kind(), v2.Type())v2Args := make([]reflect.Value, 1)v2Args[0] = reflect.ValueOf("你好")v2.Call(v2Args)// 有参有返回值v3 := reflect.ValueOf(f3)fmt.Println(v3.Kind(), v3.Type())v3Args := make([]reflect.Value, 2)v3Args[0] = reflect.ValueOf("不好")v3Args[1] = reflect.ValueOf("aaa")v3.Call(v3Args)
}

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

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

相关文章

全网最适合入门的面向对象编程教程:07 类和对象的Python实现-类型注解-提高代码可读性的利器

本文对类型注解的定义、使用原因进行了基本介绍,同时对使用typing模块实现类型提示和类型检查进行了基本讲解,通过使用类型注解可以让开发者更清晰地了解函数和变量的预期类型。全网最适合入门的面向对象编程教程:07 类和对象的 Python 实现-类型注解-提高代码可读性的利器 …

训练记录(Jul.)

7/2 AT_abc217_f *提高+/省选- 设 \(f_{l, r}\) 为把 \([l, r]\) 消去的方案数。 P3607 [USACO17JAN] Subsequence Reversal P *省选/NOI- CF1922F *2500 状态很好想,之前是因为转移成环所以没补,结果发现也可以没环。 \(f_{l, r, x}\) 表示把 \([l, r]\) 推平成 \(x\) 的…

Ubuntu24.04下Docker安装与配置

安装docker 官方教程加上代理 sudo apt-get updatesudo apt-get install ca-certificates curlsudo install -m 0755 -d /etc/apt/keyringscurl指定代理 sudo curl -x http://127.0.0.1:7897 -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.…

idea中配置Maven

主要修改两个地方:如上图。 注意: 1、如果本地仓库地址不变化,只有一个原因,就是maven/conf/settings.xml配置文件编写错误!仔细检查即可! 2、一定保证User settings file对应之前修改的settings.xml的路径,若 不一致,选中Override复选框,手动选择配置文件

linux tinydrm vs fbtft 性能对比测试

linux tinydrm vs fbtft 性能对比测试 本文将通过若干组对照试验,然后根据实验得出的数据,计算在使用fbdev的情况下,tinydrm相较于fbtft的提升幅度。免责声明:本人时间、精力有限,实验中的测试数据量较小,所以不建议将本文中的数据用于比较严谨的场景。测试环境开发板 树…

七月二日 python完成简单围棋游戏

第二天 最近,数据结构的小学期,这两天主要是完成我自己的课题设计完成围棋游戏。 【题目43】围棋游戏 设计一个简易的围棋游戏。盘面有纵横各十九条等距离、垂直交叉的平行线,共构成361个交叉点(以下简称为"点")。棋子分黑白两色。对局双方各执一色棋子,黑先白…

【vscode】vscode通过端口访问本地html页面(Live Server)

在学习mapbox过程中,发现有的图片,如果直接浏览器路径打开html文件,图片不出来,报错,得用服务的形势来访问!!!相信坚持的力量,日复一日的习惯.

基于VLC可见光通信的室内光通信信道信噪比分析matlab仿真

1.算法运行效果图预览2.算法运行软件版本 matlab2022a3.部分核心程序Pr = POW_all.*H; % 接收功率(毫瓦) POW_r = Pr./1000; % 接收功率(瓦) Pr_dbm = 10.*log10(POW_r); % 接收功率(dBm)%信噪比(SNR Ib = 202e-6; % 背景光子通量 No = 2…

JAVA文件IO流

基本的目录、文件操作,常用的IO输入输出流类介绍和使用。一、目录及文件操作Java中File类(文件类)以抽象的方式代表文件名和目录路径名,File对象则代表了磁盘中实际存在的文件和目录。File类不仅仅提供灵活的构造方法,同时还可以用于文件和目录的创建、文件的查找和文件的删…

[JLU] 数据结构与算法上机题解思路分享-第三次上机

这是吉林等通知大学数据结构与算法上机题的题解思路,没有精妙的解法,只是一个记录罢前言 首先,请务必自己尽全力尝试实现题目,直接看成品代码,思维就被拘束了,也很容易被查重。 这里只是思路解析的博客,代码仓库在 JLU_Data_Structures_Record 希望你能在这里找到你想要…

Google 发布了最新的开源大模型 Gemma 2,本地快速部署和体验

Google 重磅发布了最新版大语言模型Gemma 2,其中 90亿 参数版本适合我们个人在笔记本本地部署,老牛同学通过本文和大家一起,通过2种方式快速部署和体验,当然这2种快速部署模型的方式,也同样适用于其他大模型……Gemma 2 是 Google 最新发布的开源大语言模型。它有两种规模…

ros - slam - microros - 两轮差速模型运动学 - 运动学逆解

上一节我们推导并在代码中实现了运动学正解,本节我们来学习下运动学逆解,实现给定线速度和角速度,计算出轮子达到怎样的转速才能达到这个速度。 一、逆解推导我们直接用正解结果进行求逆解即可。 二、编写代码继续在上一节中的代码Kinematics.cpp中完善即可。void Kinematic…

vscode 中code-runner插件 py配置

"code-runner.executorMap": {"javascript": "node","python": "$pythonPath $fullFileName",}本文来自博客园,作者:__username,转载请注明原文链接:https://www.cnblogs.com/code3/p/18280704

vscode code-runner配置

"code-runner.executorMap": {"javascript": "node","python": "$pythonPath $fullFileName",}本文来自博客园,作者:__username,转载请注明原文链接:https://www.cnblogs.com/code3/p/18280704

[IOT2050 question] Unable to listen on http://127.0.0.1:1880/ 端口被占用错误

1. 背景第一次连接node-red的时候,一直出现错误Unable to listen on http://127.0.0.1:1880/。如下:2. 原因分析估计是早前利用iot2050setup小工具把node-red设置为开机自动启动项了,导致1880端口一直被占用。3. 验证首先查看端口是否真的被占用,利用sudo netstat -ltup命令…

实战篇——SQL注入sqli-labs-master靶场实战二

实战篇——SQL注入sqli-labs-master靶场实战(2) SQL注入的高级利用 (1) 宽字节注入 有时后端会对用户输入的特殊字符进行转义处理,这时普通的注入方式就会失效。对于成对的单引号,可以通过十六进制编码的方式绕过转义;而对于单个的单引号,当数据库的编码格式为GBK时,就要用…

代码随想录算法训练营第四十五天 | 打家劫舍

198.打家劫舍 题目链接 文章讲解 视频讲解dp[j]: 表示投到第j家最多能偷dp[j]的钱 递推公式: dp[j] = max(dp[j-2] + nums[j], dp[j-1]) 初始化:dp[0] = nums[0], dp[1] = max(dp[0], dp[1]) 遍历顺序:从小到大 打印dp数组class Solution { public:int rob(vector<int>…

使用开源ntfy消息推送服务发布通知实现全平台接收通知

说明:ntfy源代码:https://github.com/binwiederhier/ntfy.git 官方未编译Windows版本,本人编译最新版本:(链接:https://pan.baidu.com/s/1pMsfqNb5FKHawTLUBTgjQA?pwd=f84u提取码:f84u) 服务部署系统:Windows Server 2019或其他Windows系统简介 ntfy是一个开源的消息…

上海市小区地下室非机动车辆(电动自行车、自行车)坡道设计评级指南 All In One

上海市小区地下室非机动车辆(电动自行车、自行车)坡道设计评级指南 All In One 非机动车辆地下夹层坡道反人类设计 为什么要这么设计? 设计的参考依据是什么? 设计师有去亲身体验自己的设计成果吗? 非机动车(电动自行车、自行车)坡道设计评级指南上海市小区地下室非机动车辆…