当前位置: 首页 > news >正文

【golang长途旅行第32站】反射

反射

应用场景

  1. 序列化与反序列化
  2. ORM 框架
  3. 依赖注入(DI)框架
  4. 动态函数/方法调用

Go语言反射机制要点

Go语言的反射机制主要有以下特点:

  1. 动态类型检查 - 允许程序在运行时获取变量的类型(Type)、类别(Kind)和值(Value)信息

  2. 结构体分析 - 对于结构体类型,可以进一步获取其包含的字段和方法等详细信息

  3. 动态操作 - 支持在运行时修改变量的值以及调用与之关联的方法

  4. 使用方式 - 需要导入标准库中的"reflect"包来实现反射功能

这些特性使得Go程序能够在运行时动态地检查和操作各种类型的变量,为编写更灵活的代码提供了可能。

重要函数和机制

  1. 基础反射函数

    1. ​reflect.TypeOf(变量名)​​
      功能:获取变量的类型信息
      返回值:reflect.Type类型
      用途:用于分析变量的静态类型信息
    2. ​reflect.ValueOf(变量名)​​
      功能:获取变量的值信息
      返回值:reflect.Value类型(结构体类型)
      用途:通过reflect.Value可以获取变量的详细信息,如字段值、方法等
  2. 类型转换关系
    变量、interface{}和reflect.Value三者之间可以相互转换:
    变量 → interface{} → reflect.Value
    reflect.Value → interface{} → 变量
    这种转换在实际开发中经常使用,特别是在需要处理未知类型数据时
    代码示例:
    // 反射类型转换示例函数
    func reflectConvert(b interface{}) {
    // 第一步:interface{} → reflect.Value
    rVal := reflect.ValueOf(b)

    // 第二步:reflect.Value → interface{}
    iVal := rVal.Interface()

    // 第三步:interface{} → 原类型(使用类型断言)
    // 假设原类型为Stu结构体
    v := iVal.(Stu)
    }

为何要以interface{}类型传入呢,不直接以结构体传入?这种情况的出现自然有缘由。
如果指定某个结构体类型,那么这个函数就只适用于这一个结构体了,如果使用接口,那只需要传入的结构体实现了这个接口,就可以作为参数传入,使代码量减少,维护性增强

快速入门

  1. 对基本数据类型进行反射
    代码示例:
    func Change(b interface{}) {
    rType := reflect.TypeOf(b)
    rValue := reflect.ValueOf(b)
    fmt.Printf(“%v,%v,%T,%v\n”, rType, rValue, b, b)
    fmt.Println(2 + b.(int))
    fmt.Println(2 + rValue.Int())
    }
    func main() {
    a := 10
    Change(a)
    }

输出结果:
int,10,int,10
12
12

注意点:虽然rValue的输出是10,但是2+rValue是跑不通的,因为reflect包实现了运行时反射,但是在编译时,还是处于静态,rValue还是被当作成一个refelct.interface类型,不同类型之间不能相加

注意事项

  1. ​reflect.Value.Kind()的作用​
    该函数用于获取一个变量的“类别(Kind)”,其返回值是一个预定义的常量(例如 Int, String等)。使用者需要查阅官方手册来了解所有可能的常量值。
  2. ​​“类型(Type)”与“类别(Kind)”的区别与联系​
  • ​Type​ 指变量明确的类型。
  • ​Kind​ 指变量底层的基本类别。
  • 两者可能相同,也可能不同。
  • ​举例来说:​​
    • 变量 num int:其 Type 是 int,Kind 也是 int(此时相同)。

    • 变量 stu Student(一个自定义结构体):其 Type 是 包名.Student,而 Kind 是 struct(此时不同)。

  1. 使用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,比如x是int类型,那么就应该使用reflect.Value(x).Int(),而不能使用其它的,否则报panic。如果是结构体,就用类型断言。
  2. 通过反射修改内容时,需要传入的是地址
    代码示例:
    func reflects(b interface{}) {
    rValue := reflect.ValueOf(b)
    fmt.Println(rValue.Elem())
    rValue.Elem().SetInt(21)
    fmt.Println(rValue.Elem())
    }
    func main() {
    num := 2
    reflects(&num)
    }

输出结果
2
21

其中,rValue.Elem()类似于rValue,但是由于rValue是reflect.Value类型,所以不能使用rValue

  1. Method()函数,用于获得某个方法,此时对于方法的排序是根据方法的字母ASCII由小到大排列
http://www.dtcms.com/a/351818.html

相关文章:

  • 【机器学习深度学习】连续微调与权重合并的陷阱与最佳实践
  • 修改C盘缓存文件路径
  • MongoDB /redis/mysql 界面化的数据查看页面App
  • UCIE Specification详解(八)
  • 在MiniOB源码中学习使用Flex与Bison解析SQL语句-第一节
  • Rust 环境搭建与 SeekStorm 项目编译部署(支持中文)
  • Robrain V2.0正式登场:落地人形机器人,引爆智能进化革命
  • Ubuntu操作系统下使用mysql、mongodb、redis
  • [特殊字符] CentOS 7 升级 OpenSSH 10.0p2 完整教程(含 Telnet 备份)
  • 如果 我退休了
  • 汽车域控中Hypervisor方案极致安全原理与弊端
  • APP UI自动化测试的思路总结
  • 破解豆瓣Ajax动态加载:Python爬取完整长评论和短评
  • Java面试实战系列【JVM篇】- JVM内存结构与运行时数据区详解(私有区域)
  • 数据结构:链式队列尝试;0826
  • poi生成word固定表格列宽
  • Spring - 文件上传与下载:真正的企业开发高频需求——Spring Boot文件上传与下载全场景实践指南
  • 位运算卡常技巧详解
  • Charles抓包微信小程序请求响应数据
  • 信号无忧,转决千里:耐达讯自动化PROFIBUS集线器与编码器连接术
  • 快速了解卷积神经网络
  • springweb项目中多线程使用详解
  • 问:单证硕士含金量是否不足?
  • 【Linux 进程】进程程序替换
  • 【GitHub】使用SSH与GitHub交互
  • 工业大模型五层架构全景解析:从算力底座到场景落地的完整链路
  • PyCharm注释详解:TODO、文档注释、注释
  • MySQL 索引:结构、对比与操作实践指南
  • 【合适新人】预测图片教程——如何随机抽取验证集图片进行可视化推理!(附完整代码)
  • DigitalOcean GPU 选型指南(三):中端AI GPU性价比之王 RTX 4000 Ada、A4000、A5000