Go语言反射获取类型属性和方法示例
作者:aoho 发布时间:2024-05-05 09:32:42
reflect.StructField 和 reflect.Method
如果变量是一个结构体,我们还可以通过结构体域类型对象 reflect.StructField 来获取结构体下字段的类型属性。Type 接口下提供了不少用于获取字段结构体域类型对象的方法,我们主要介绍以下几个接口:
// 获取一个结构体内的字段数量
NumField() int
// 根据 index 获取结构体内的成员字段类型对象
Field(i int) StructField
// 根据字段名获取结构体内的成员字段类型对象
FieldByName(name string) (StructField, bool)
通过以上的 3 个方法,我们可以轻易地拿到一个结构体变量内的所有成员字段的类型对象 reflect.StructField。通过 reflect.StructField,我们可以知道成员字段所属的类型和种类,其内主要由以下的属性:
type StructField struct {
// 成员字段的名称
Name string
// 成员字段 Type
Type Type
// Tag
Tag StructTag
// 字节偏移
Offset uintptr
// 成员字段的 index
Index []int
// 成员字段是否公开
Anonymous bool
}
StructField
StructField 中提供了 Type 用于获取字段的的类型信息,而 StructTag 一般用来描述结构体成员字段的额外信息,比如在 JSON 进行序列化和对象映射时会被使用。StructTag 一般由一个或者多个键值对组成,一个简单的例子如下:
ID string `json:"id"`
键与值使用 : 分隔,值用 "" 括起来, 键值对之间使用空格分隔。上面例子中说明 ID 字段在 JSON 序列化时会被变成 id 。
遍历 Hero 结构体
接下来,我们通过遍历 Hero 结构体,获取其内字段的类型并输出,代码如下所示:
func main() {
typeOfHero := reflect.TypeOf(Hero{})
// 通过 #NumField 获取结构体字段的数量
for i := 0 ; i < typeOfHero.NumField(); i++{
fmt.Printf("field' name is %s, type is %s, kind is %s\n", typeOfHero.Field(i).Name, typeOfHero.Field(i).Type, typeOfHero.Field(i).Type.Kind())
}
// 获取名称为 Name 的成员字段类型对象
nameField, _ := typeOfHero.FieldByName("Name")
fmt.Printf("field' name is %s, type is %s, kind is %s\n", nameField.Name, nameField.Type, nameField.Type.Kind())
}
预期的结果如下所示:
field' name is Name, type is string, kind is string
field' name is Age, type is int, kind is int
field' name is Speed, type is int, kind is int
field' name is Name, type is string, kind is string
上述代码中先使用 Type#NumField 获取 Hero 结构体中字段的数量,再通过 typeOfHero#Field 根据 index 获取每个字段域类型对象并打印它们的类型信息。代码最后还演示如何通过 typeOfHero#FieldByName 获取了字段名为 Name 的字段域类型对象。
Method
除了获取结构体下的字段域类型对象,Type 还提供方法获取接口下方法的方法类型对象 Method,接口方法描述如下:
// 根据 index 查找方法
Method(int) Method
// 根据方法名查找方法
MethodByName(string) (Method, bool)
// 获取类型中公开的方法数量
NumMethod() int
获取到的方法类型描述对象 Method 描述了方法的基本信息,包括方法名,方法类型等,代码如下所示:
type Method struct {
// 方法名
Name string
// 方法类型
Type Type
// 反射对象,可用于调用方法
Func Value
// 方法的index
Index int
}
在 Method 中 Func 字段是一个反射值对象,可用于进行方法的调用。如果 Method 是来自于接口类型反射得到的 Type ,那么 Func 传递的第一个参数需要为实现方法的 * ,这部分区别我们将在 Value 中进行具体的介绍。
我们可以通过 Type 中提供的方法获取接口 Person 中方法的方法类型对象,代码如下所示:
func main() {
// 声明一个 Person 接口,并用 Hero 作为 *
var person Person = &Hero{}
// 获取接口Person的类型对象
typeOfPerson := reflect.TypeOf(person)
// 打印Person的方法类型和名称
for i := 0 ; i < typeOfPerson.NumMethod(); i++{
fmt.Printf("method is %s, type is %s, kind is %s.\n", typeOfPerson.Method(i).Name, typeOfPerson.Method(i).Type, typeOfPerson.Method(i).Type.Kind())
}
method, _ := typeOfPerson.MethodByName("Run")
fmt.Printf("method is %s, type is %s, kind is %s.\n", method.Name, method.Type, method.Type.Kind())
}
预期的输出结果如下所示:
method is Run, type is func(*main.Hero), kind is func
method is SayHello, type is func(*main.Hero, string), kind is func
method is Run, type is func(*main.Hero) string, kind is func.
除了通过 typeOfPerson#Method 根据 index 获取方法类型对象,还可以使用 typeOfPerson#MethodByName 根据方法名查找对应的方法类型对象。从输出结果可以看出,方法的种类均为 func,而类型则为方法的声明。
小结
本文主要介绍了 Go 语言的反射基础 reflect.StructField 和 reflect.Method。通过反射,我们可以拿到类型信息和定义的方法等,Go 的反射实现了反射的大多数功能,获取类型信息需要配合使用标准库中的词法、语法解析器和抽象语法数对源码进行扫描。下一篇文章将会继续介绍 Go 语言的反射 reflect.Value 反射值对象相关内容。
来源:https://juejin.cn/post/6976157798027493384


猜你喜欢
- 本文讲述了python开发之IDEL(Python GUI)的使用方法。分享给大家供大家参考,具体如下:在安装完Python后,我们希望能够
- 考点:将字典转换为XML文档;将XML文档转换为字典。面试题1.面试题一:如何将一个字典转换为XML文档,并将该XML文档保存为文本文件。2
- DQLDQL英文全称是Data Query Language(数据查询语言),数据查询语言,用来查询数据库中表的记录。基本语法DQL 查询语
- 具体代码如下所示:import smtplib, email, os, timefrom email.mime.multipart impo
- 说明一直想做一个基于VUE的项目,但是因为项目往往要涉及到后端的知识(不会后端真的苦),所以就没有一直真正的动手去做一个项目。直到发现Git
- python __init__.py 和 __all__作用一、__init__.py1、导入文件夹包的时候,会运行写在该文件夹包下的__i
- 本文实例为大家分享SQL SERVER数据库备份的具体代码,供大家参考,具体内容如下/** 批量循环备份用户数据库,做为数据库迁
- 很简单的代码,记录一下。 import Image image =
- 前言最近更新了Python版本,准备写个爬虫,意外的发现urllib库中属性不存在urlopen,于是各种google,然后总结一下给出解决
- Django是一个基于Python Web框架的高级Web框架,允许快速开发和干净,务实的设计。今天,我们将创建一个待办事项应用程序,以了解
- Python 下的单例模式要点:1.某个类只能有一个实例;2.它必须自行创建这个实例;3.它必须自行向整个系统提供这个实例方法:重写new函
- 建议先看vue瀑布流组件上拉加载更多再来食用本文,如果直接想看源码文末就是~文末新增组件优化,之所以没有删优化前的代码是想让以后自己还能看到
- Oracle9i中提供强大的迁移功能,可以从多种数据库向Oracle迁移数据。Oracle新发行的迁移工具提供了从Access2
- 使用Python的人都知道range()函数和list很方便,今天再用到他的时候发现了很多以前看到过但是忘记的细节。这里记录一下range(
- (1)标准类型操作符(所有的集合类型)成员关系 (in, not in) &nbs
- 版本:python3.7功能,开发一个用户访问的页面,支持图片上传,并将其保存在服务器。项目结构:app.py文件内容如下:from fla
- 引子Tornado 是一个网络异步的的web开发框架, 并且可以利用多进程进行提高效率, 下面是创建一个多进程 tornado 程序的例子.
- 我们将研究一种判别式分类方法,其中直接学习评估 g(x)所需的 w 参数。我们将使用感知器学习算法。感知器学习算法很容易实现,但为了节省时间
- Linux下MySQL数据库的主从同步配置的好处是可以把这个方式当做是一个备份的方法,用来实现读写分离,缓解一个数据库的压力。让运行海量数据
- 生命游戏的算法就不多解释了,百度一下介绍随处可见。因为网上大多数版本都是基于pygame,matlab等外部库实现的,二维数组大多是用num