【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由小到大排列
相关推荐
tao355667几秒前
【Python刷力扣hot100】49. Group Anagrams
开发语言·python·leetcode
龙腾AI白云3 分钟前
大模型-扩散模型(Diffusion Model)原理讲解(4)
开发语言
爱吃小胖橘35 分钟前
Lua语法(2)
开发语言·unity·lua
_Power_Y36 分钟前
SSM面试题学习
java·开发语言·学习
武子康1 小时前
大数据-118 - Flink 批处理 DataSet API 全面解析:应用场景、代码示例与优化机制
大数据·后端·flink
不要再敲了1 小时前
Spring Security 完整使用指南
java·后端·spring
SccTsAxR1 小时前
[初学C语言]关于scanf和printf函数
c语言·开发语言·经验分享·笔记·其他
IT_陈寒1 小时前
Redis 高性能缓存设计:7个核心优化策略让你的QPS提升300%
前端·人工智能·后端
害恶细君1 小时前
【超详细】使用conda配置python的开发环境
开发语言·python·jupyter·pycharm·conda·ipython
brzhang2 小时前
高通把Arduino买了,你的“小破板”要变“AI核弹”了?
前端·后端·架构