🗒️Golang 反射
00 分钟
2023-9-23
2023-12-9
type
status
date
slug
summary
tags
category
icon
password

Golang 反射

反射的引子

有时我们需要写一个函数,这个函数有能力统一处理各种值类型,而这些类型可能无法共享同一个接口,也可能布局未知,也有可能这个类型在我们设计函数时还不存在,这个时候我们就可以用到反射。
1、空接口可以存储任意类型的变量,那我们如何知道这个空接口保存数据的类型是什么?值是什么呢?
  1. 可以使用类型断言
  1. 可以使用反射实现,也就是在程序运行时动态的获取一个变量的类型信息和值信息。
2、把结构体序列化成 json 字符串,自定义结构体 Tag 标签的时候就用到了反射
3、后期我们会给大家讲 ORM 框架,这个 ORM 框架就用到了反射技术
  • *ORM:**对象关系映射(Object Relational Mapping,简称 ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。

反射的基本介绍

反射是指在程序运行期间对程序本身进行访问和修改的能力。正常情况程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分。在运行程序时,程序无法获取自身的信息。支持反射的语言可以在程序编译期将变量的反射信息,如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息,并且有能力修改它们。
Golang 中反射可以实现以下功能:
1、反射可以在程序运行期间动态的获取变量的各种信息,比如变量的类型 类别
2、如果是结构体,通过反射还可以获取结构体本身的信息,比如结构体的字段、结构体的方法、结构体的 tag。
3、通过反射,可以修改变量的值,可以调用关联的方法
Go 语言中的变量是分为两部分的 :
  • 类型信息:预先定义好的元信息。
  • 值信息:程序运行过程中可动态变化的。
在 GoLang 的反射机制中,任何接口值都由是一个具体类型具体类型的值两部分组成的。
在 GoLang 中,反射的相关功能由内置的 reflect 包提供,任意接口值在反射中都可以理解为由 reflect.Type 和 reflect.Value 两 部 分 组 成 , 并 且 reflect 包 提 供 了 reflect.TypeOfreflect.ValueOf 两个重要函数来获取任意对象的 Value 和 Type。

reflect.TypeOf()获取任意值的类型对象

在 Go 语言中,使用 reflect.TypeOf()函数可以接受任意 interface{}参数,可以获得任意值的类型对象(reflect.Type),程序通过类型对象可以访问任意值的类型信息。
type Name type Kind
在反射中关于类型还划分为两种:
类型(Type)和种类(Kind)。因为在 Go 语言中我们可以使用 type 关键字构造很多自定义类型,而种类( Kind )就是指底层的类型,但在反射中,当需要区分指针、结构体等大品种的类型时,就会用到种类(Kind。 举个例子,我们定义了两个指针类型和两个结构体类型,通过反射查看它们的类型和种类。
Go 语言的反射中像数组、切片、Map、指针等类型的变量,它们的.Name()都是返回空。
reflect 包中定义的 Kind 类型如下:

reflect.ValueOf()

reflect.ValueOf()返回的是 reflect.Value 类型,其中包含了原始值的值信息。reflect.Value 与原始值之间可以互相转换。
reflect.Value 类型提供的获取原始值的方法如下:
notion image

通过反射获取原始值演示 1

通过反射获取原始值演示 2

通过反射设置变量的值

想要在函数中通过反射修改变量的值,需要注意函数参数传递的是值拷贝,必须传递变量地址才能修改变量值。而反射中使用专有的 Elem()方法来获取指针对应的值。

结构体反射

与结构体相关的方法

任意值通过 reflect.TypeOf()获得反射对象信息后,如果它的类型是结构体,可以通过反射值对象(reflect.Type)的 NumField()和 Field()方法获得结构体成员的详细信息。
reflect.Type 中与获取结构体成员相关的的方法如下表所示。
notion image
notion image

StructField 类型

StructField 类型用来描述结构体中的一个字段的信息。StructField 的定义如下:

结构体反射示例

当我们使用反射得到一个结构体数据之后可以通过索引依次获取其字段信息,也可以通过字段名去获取指定的字段信息。
1、获取结构体属性,获取执行结构体方法
2、修改结构体方法

不要乱用反射

反射是一个强大并富有表现力的工具,能让我们写出更灵活的代码。但是反射不应该被滥用,
原因有以下两个。
  1. 基于反射的代码是极其脆弱的,反射中的类型错误会在真正运行的时候才会引发 panic,那很可能是在代码写完的很长时间之后。
  1. 大量使用反射的代码通常难以理解。

评论
Loading...