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

【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.xdnf.cn/news/18747.html

相关文章:

  • 【大前端】React统计所有网络请求的成功率、失败率以及统一入口处理失败页面
  • 基于Android的超市购物系统的设计与实现、基于android的在线商城app/基于android的在线销售系统app#android
  • CVPR论文速递 | DL3DV-10K:10K+真实场景,打破三维视觉数据荒!
  • (论文速读)Prompt Depth Anything:让深度估计进入“提示时代“
  • 抽签占卜抖音快手微信小程序看广告流量主开源
  • 基于SpringBoot的演唱会网上订票系统的设计与实现(代码+数据库+LW)
  • 深入浅出理解支持向量机(SVM):从原理到实践
  • 《鸿蒙开发 3 天速成:核心知识点 + 实战案例精讲》
  • Uniapp(Vue2)Api请求封装
  • 解决VSCode无法下载服务器端 Server问的题
  • vue3 + jsx 中使用native ui 组件插槽
  • 使用 mcp-use 构建极简 Web 自动化测试智能体「喂饭教程」
  • http与https配置
  • 管理网络安全
  • FreeRTOS学习笔记(四):任务执行与切换
  • 入门Ubuntu操作系统
  • 类型签名,位置参数,关键字参数
  • 【Jetson】基于llama.cpp部署gpt-oss-20b(推理与GUI交互)
  • 利用Certbot生成ssl证书配置到nginx
  • Redis--2
  • 从下载到运行:MySQL 详细安装配置完整教程
  • Cloudflare 推出 GenAI 安全工具,守护企业数据
  • AI在提升阅读效率的同时,如何加强理解深度?
  • 2025中国生物制造科技创新论坛为何“花落”常德?
  • arm问题
  • 编写Linux下usb设备驱动方法:probe函数中要进行的工作
  • HTML+CSS+JavaScript实现的AES加密工具网页应用,包含完整的UI界面和加密/解密功能
  • 集成电路学习:什么是ONNX开放神经网络交换
  • 网络编程——TCP、UDP
  • ADC-工业信号采集卡-K004规格书