【Golang】Golang进阶系列教程--为什么 Go 语言 struct 要使用 tags

这篇具有很好参考价值的文章主要介绍了【Golang】Golang进阶系列教程--为什么 Go 语言 struct 要使用 tags。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

在 Go 语言中,struct 是一种常见的数据类型,它可以用来表示复杂的数据结构。在 struct 中,我们可以定义多个字段,每个字段可以有不同的类型和名称。

除了这些基本信息之外,Go 还提供了 struct tags,它可以用来指定 struct 中每个字段的元信息。
在本文中,我们将探讨为什么 Go 语言中需要使用 struct tags,以及 struct tags 的使用场景和优势。

struct tags 的使用

struct tags 使用还是很广泛的,特别是在 json 序列化,或者是数据库 ORM 映射方面。
【Golang】Golang进阶系列教程--为什么 Go 语言 struct 要使用 tags,# GoLang,golang,开发语言,后端

在定义上,它以 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 的库的列表,我复制在下面了,感兴趣的同学可以看看源码,再继续深入学习。

Tag Documentation
xml pkg.go.dev/encoding/xm…
json pkg.go.dev/encoding/js…
asn1 pkg.go.dev/encoding/as…
reform pkg.go.dev/gopkg.in/re…
dynamodb docs.aws.amazon.com/sdk-for-go/…
bigquery pkg.go.dev/cloud.googl…
datastore pkg.go.dev/cloud.googl…
spanner pkg.go.dev/cloud.googl…
bson pkg.go.dev/labix.org/v…, pkg.go.dev/go.mongodb.…
gorm pkg.go.dev/github.com/…
yaml pkg.go.dev/gopkg.in/ya…
toml pkg.go.dev/github.com/…
validate github.com/go-playgrou…
mapstructure pkg.go.dev/github.com/…
parser pkg.go.dev/github.com/…
protobuf github.com/golang/prot…
db github.com/jmoiron/sql…
url github.com/google/go-q…
feature github.com/nikolaydubi…

以上就是本文的全部内容。

参考文章:

github.com/golang/go/w…文章来源地址https://www.toymoban.com/news/detail-613596.html

到了这里,关于【Golang】Golang进阶系列教程--为什么 Go 语言 struct 要使用 tags的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 是时候回答【我为什么要学习 Go 语言(golang)】这个问题了

    想必每个人在学习新事物之前,都会扪心自问:“我为什么要学习它呢?” 正如我们读 四大名著 一般,也只有在您读过了 四大名著 后,再细看中国几千年历史不就是 天下大势合久必分,分久必合 ,再者,便是与友数人相聚,席间您述说您通勤时所遇到有意思的事了,而您

    2023年04月09日
    浏览(18)
  • 【Golang】一篇文章带你快速了解Go语言&为什么你要学习Go语言

    目录 1. 为什么互联网世界需要Go语言 1.1 硬件限制:摩尔定律已然失效  1.2 Go语言为并发而生 1.3 Go性能强悍 1.4 Go语言简单易学 1.4.1 语法简洁 1.4.2 代码风格统一 1.4.3开发效率高  2.Go语言的诞生与发展 2.1什么是Go语言   2.2 Go语言的诞生 2.3 Go Gopher——Go语言的吉祥物 3. 为什么

    2024年02月04日
    浏览(29)
  • 【Golang】Golang进阶系列教程--Go 语言切片是如何扩容的?

    在 Go 语言中,有一个很常用的数据结构,那就是切片(Slice)。 切片是一个拥有相同类型元素的可变长度的序列,它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。 切片是一种引用类型,它有三个属性:指针,长度和容量。 底层源码定义如下: 指针: 指向

    2024年02月14日
    浏览(25)
  • 【Golang】Golang进阶系列教程--Go 语言 map 如何顺序读取?

    Go 语言中的 map 是一种非常强大的数据结构,它允许我们快速地存储和检索键值对。 然而,当我们遍历 map 时,会有一个有趣的现象,那就是输出的键值对顺序是不确定的。 先看一段代码示例: 当我们多执行几次这段代码时,就会发现,输出的顺序是不同的。 首先,Go 语言

    2024年02月14日
    浏览(25)
  • 【Golang】Golang进阶系列教程--Go 语言数组和切片的区别

    在 Go 语言中,数组和切片看起来很像,但其实它们又有很多的不同之处,这篇文章就来说说它们到底有哪些不同。 数组和切片是两个常用的数据结构。它们都可以用于存储一组相同类型的元素,但在底层实现和使用方式上存在一些重要的区别。 Go 中数组的长度是不可改变的

    2024年02月15日
    浏览(24)
  • Go 语言为什么很少使用数组?

    大家好,我是 frank,「Golang 语言开发栈」公众号作者。 01 介绍 在 Go 语言中,数组是一块连续的内存,数组不可以扩容,数组在作为参数传递时,属于值传递。 数组的长度和类型共同决定数组的类型,不同类型的数组之间不可以比较,否则在编译时会报错。 因为数组的一些

    2024年02月04日
    浏览(26)
  • Go 语言为什么不支持并发读写 map?

    大家好,我是 frank ,「 Golang 语言开发栈」公众号作者。 01 介绍 在 Go 语言项目开发中,我们经常会使用哈希表 map ,它的时间复杂度是 O(1) ,Go 语言中的 map 使用开放寻址法避免哈希碰撞。 Go 语言中的 map 并非原子操作,不支持并发读写操作。 Go 官方认为 map 在大多数情况下

    2024年02月02日
    浏览(29)
  • 为什么选择Go语言编写网络应用程序

    关注公众号【爱发白日梦的后端】分享技术干货、读书笔记、开源项目、实战经验、高效开发工具等,您的关注将是我的更新动力! 作为一名后端开发者,你一定对选择合适的编程语言来编写网络应用程序非常重视。在众多的编程语言中,Go语言(Golang)凭借其独特的特性和

    2024年02月02日
    浏览(46)
  • Go 语言为什么建议多使用切片,少使用数组?

    大家好,我是 frank,「Golang 语言开发栈」公众号作者。 01 介绍 在 Go 语言中,数组固定长度,切片可变长度;数组和切片都是值传递,因为切片传递的是指针,所以切片也被称为“引用传递”。 读者朋友们在使用 Go 语言开发项目时,或者在阅读 Go 开源项目源码时,发现很少

    2024年02月03日
    浏览(32)
  • 为什么说 Go 语言字符串是不可变的?

    原文链接: 为什么说 Go 语言字符串是不可变的? 最近有读者留言说,平时在写代码的过程中,是会对字符串进行修改的,但网上都说 Go 语言字符串是不可变的,这是为什么呢? 这个问题本身并不困难,但对于新手来说确实容易产生困惑,今天就来回答一下。 首先来看看它

    2024年02月07日
    浏览(23)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包