为什么 Go 语言 struct 要使用 tags
原文链接:为什么 Go 语言 struct 要使用 tags
在 Go 语言中,struct 是一种常见的数据类型,它可以用来表示复杂的数据结构。在 struct 中,我们可以定义多个字段,每个字段可以有不同的类型和名称。
除了这些基本信息之外,Go 还提供了 struct tags,它可以用来指定 struct 中每个字段的元信息。
在本文中,我们将探讨为什么 Go 语言中需要使用 struct tags,以及 struct tags 的使用场景和优势。
struct tags 的使用
struct tags 使用还是很广泛的,特别是在 json 序列化,或者是数据库 ORM 映射方面。

在定义上,它以 key:value 的形式出现,跟在 struct 字段后面,除此之外,还有以下几点需要注意:
使用反引号
在声明 struct tag 时,使用反引号 ` 包围 tag 的值,可以防止转义字符的影响,使 tag 更容易读取和理解。例如:
type User struct {
ID int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Email string `json:"email" db:"email"`
}
避免使用空格
在 struct tag 中,应该避免使用空格,特别是在 tag 名称和 tag 值之间。使用空格可能会导致编码或解码错误,并使代码更难以维护。例如:
// 不规范的写法
type User struct {
ID int `json: "id" db: "id"`
Name string `json: "name" db: "name"`
Email string `json: "email" db: "email"`
}
// 规范的写法
type User struct {
ID int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Email string `json:"email" db:"email"`
}
避免重复
在 struct 中,应该避免重复使用同一个 tag 名称。如果重复使用同一个 tag 名称,编译器可能会无法识别 tag,从而导致编码或解码错误。例如:
// 不规范的写法
type User struct {
ID int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Email string `json:"email" db:"name"`
}
// 规范的写法
type User struct {
ID int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Email string `json:"email" db:"email"`
}
使用标准化的 tag 名称
为了使 struct tag 更加标准化和易于维护,应该使用一些标准化的 tag 名称。
例如,对于序列化和反序列化,可以使用 json、xml、yaml 等;对于数据库操作,可以使用 db。
type User struct {
ID int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Password string `json:"-" db:"password"` // 忽略该字段
Email string `json:"email" db:"email"`
}
其中,Password 字段后面的 - 表示忽略该字段,也就是说该字段不会被序列化或反序列化。
多个 tag 值
如果一个字段需要指定多个 tag 值,可以使用 , 将多个 tag 值分隔开。例如:
type User struct {
ID int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Email string `json:"email,omitempty" db:"email,omitempty"`
}
其中 omitempty 表示如果该字段值为空,则不序列化该字段。
struct tags 的原理
Go 的反射库提供了一些方法,可以让我们在程序运行时获取和解析结构体标签。
介绍这些方法之前,先来看看 reflect.StructField ,它是描述结构体字段的数据类型。定义如下:
type StructField struct {
Name string // 字段名
Type Type // 字段类型
Tag StructTag // 字段标签
}
结构体中还有一些其他字段,被我省略了,只保留了和本文相关的。
在结构体的反射中,我们经常使用 reflect.TypeOf 获取类型信息,然后使用 Type.Field 或 Type.FieldByName() 获取结构体字段的 reflect.StructField,然后根据 StructField 中的信息做进一步处理。
例如,可以通过 StructField.Tag.Get 方法获取结构体字段的标签值。
下面看一段代码:
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
type Manager struct {
Title string `json:"title"`
User
}
func main() {
m := Manager{Title: "Manager", User: User{Name: "Alice", Age: 25}}
mt := reflect.TypeOf(m)
// 获取 User 字段的 reflect.StructField
userField, _ := mt.FieldByName("User")
fmt.Println("Field 'User' exists:", userField.Name, userField.Type)
// 获取 User.Name 字段的 reflect.StructField
nameField, _ := userField.Type.FieldByName("Name")
tag := nameField.Tag.Get("json")
fmt.Println("User.Name tag:", tag)
}
运行以上代码,输出结果如下:
Field 'User' exists: User {string int}
User.Name tag: "name"
struct tags 的优势
使用 struct tag 的主要优势之一是可以在运行时通过反射来访问和操作 struct 中的字段。
比如在 Go Web 开发中,常常需要将 HTTP 请求中的参数绑定到一个 struct 中。这时,我们可以使用 struct tag 指定每个字段对应的参数名称、验证规则等信息。在接收到 HTTP 请求时,就可以使用反射机制读取这些信息,并根据信息来验证参数是否合法。
另外,在将 struct 序列化为 JSON 或者其他格式时,我们也可以使用 struct tag 来指定每个字段在序列化时的名称和规则。
此外,使用 struct tag 还可以提高代码的可读性和可维护性。在一个大型的项目中,struct 中的字段通常会包含很多不同的元信息,比如数据库中的表名、字段名、索引、验证规则等等。
如果没有 struct tag,我们可能需要将这些元信息放在注释中或者在代码中进行硬编码。这样会让代码变得难以维护和修改。而使用 struct tag 可以将这些元信息与 struct 字段紧密关联起来,使代码更加清晰和易于维护。
常用的 struct tags
在 Go 的官方 wiki 中,有一个常用的 struct tags 的库的列表,我复制在下面了,感兴趣的同学可以看看源码,再继续深入学习。
以上就是本文的全部内容,如果觉得还不错的话欢迎点赞,转发和关注,感谢支持。
参考文章:
推荐阅读:
为什么 Go 语言 struct 要使用 tags的更多相关文章
- C语言struct小知识
1.C语言里的struct是不能包含成员函数的,只能有数据成员2.C语言struct定义变量只能用一下两种方式:struct { ... } x, y, z;struct point pt;直接poi ...
- C语言struct类型
在实际问题中,一组数据往往具有不同的数据类型.例如, 在学生登记表中,姓名应为字符型:学号可为整型或字符型: 年龄应为整型:性别应为字符型:成绩可为整型或实型. 显然不能用一个数组来存放这一组数据. ...
- C语言 Struct 结构体在 Java 中的体现
大一整个学期完成了 C 语言的学习,大二就进入了Java 的学习. 和C语言一样,我们都会尝试写一个小小的学生管理系统什么的,学习过 C 语言同学知道,在管理系统中 Struct 结构体是个很好用的东 ...
- c语言struct和c++struct的区别
1.定义 c语言中struct是用户自定义数据类型(UDT),是一些变量的集合体:c++中struct是抽象数据类型(ADT),能给用户提供接口,能定义成员函数,能继承,能实现多态 2.成员权限设置 ...
- 关于c语言struct和typedef
C++中使用: struct test{ int x, y;};就可以定义一个名为 test的结构体,但C中很可能编译通不过.C语言并不支持在struct后使用标示符定义结构体的名字,test将 ...
- CC+语言 struct 深层探索——CC + language struct deep exploration
1 struct 的巨大作用 面对一个人的大型C/C++程序时,只看其对struct 的使用情况我们就可以对其编写者的编程经验进行评估.因为一个大型的C/C++程序,势必要涉及一些(甚至 ...
- c语言struct和c++的class的暧昧
c语言风格的封装 数据放在一起,以引用和指针的方式传给行为c++ 认为封装不彻底 1数据和行为分开 对外提供接口 2没有权限设置 看看struct的一个例子 //data.h //c语言风格的封装 数 ...
- C 语言Struct 实现运行类型识别 RTTI
通过RTTI,能够通过基类的指针或引用来检索其所指对象的实际类型.c++通过下面两个操作符提供RTTI. (1)typeid:返回指针或引用所指对象的实际类型. (2)dynamic_cast: ...
- c语言 struct 的初始化
转自:http://www.cnblogs.com/silentjesse/archive/2013/07/30/3225212.html struct数据有3中初始化方法:顺序,C风格及C++风格的 ...
- 内存对齐-C语言struct内存占用问题
转1个写的比较全面的. http://hubingforever.blog.163.com/blog/static/17104057920122256134681/ 本文编辑整理自:http://hi ...
随机推荐
- 全新BPMN常用图形标识一览表
BPMN符号与BPMN的关系 BPMN,即业务流程建模与标记(手法),表达此类手法的即是业务流程模型示意图.业务流程示意图是由一系列的元素符号构成.作为BPMN的基础,这些符号将业务流程建模简单化.图 ...
- 夜神模拟器连接不上adb的解决办法
1.夜神模拟器连接不上adb的解决办法 转自 (https://www.jianshu.com/p/6041e64518a8) 最近给模拟器升级了版本,用了一段时间后,突然发现通过adb device ...
- JavaScript基础知识整理(引用类型-Object)
Object类型 其他的引用类型都是Object类型的实例,创建Object实例有两种方式 (1)使用构造函数 var obj = new Object(); obj.name = "xia ...
- flutter TextField 使用prefixIcon图标和文字间距问题
可以看到使用prefixIcon图标就出现间距问题.网上看了很多文章,好像是没有什么好的解决办法,也有可能是太简单了,别人懒的发(哭笑). 我把我知道的方法写出来吧 decoration: Input ...
- react实现转盘动画
转盘动画方法如下: /** * 点击转动转盘 */ const turnCircle = () => { let runDeg = +(Math.random() * 360).toFixed( ...
- 搭建react项目
1.打开新建的项目空文件夹,终端输入命令:npm init,文件夹生成package.json文件: 2.安装webpack.webpack-cli和cross-env:npm install web ...
- vue 打包后可放置在任意名称的文件夹下
1. build->utils.js: 2. build->webpack.prod.conf.js: 3. config->index.js:
- 修改mysql root密码,在workbench中导入.sql文件
修改mysql root密码: 1.如果没有配置环境变量,在 \Program Files\MySQL\MySQL Server 8.0\bin 文件下 Shit+右键打开 Powershell 窗口 ...
- miou
1. 前言 本文学习记录了机器学习中的分类常见评价指标以及分割中的MIoU. 主要有以下概念:Accuracy, Precision, Recall, Fscore,混淆矩阵,IoU及MIoU. 2. ...
- 导入ssm项目时,项目基本的配置文件
一.ssm框架基本的配置文件 上面的这些配置文件对于比较简单的ssm项目其实大同小异,逻辑上是差不多的. 在config目录下 在lib下就是各种jar包 二.导入ssm项目后,本地环境配置和项目本身 ...