【Go】结构体中Tag标识

https://blog.csdn.net/weixin_45193103/article/details/123876319
https://blog.csdn.net/qq_49723651/article/details/122005291
https://juejin.cn/post/7005465902804123679
学一点,整一点,基本都是综合别人的,弄成我能理解的内容

Tag定义

Tag用于标识结构体字段的额外属性,有点类似于注释。标准库reflect包中提供了操作Tag的方法

Tag是结构体在编译阶段关联到成员的元信息字符串,在运行的时候通过反射的机制读取出来。

结构体的字段的定义。在reflect包中,使用结构体structField表示结构体的一个字段

type StructField struct {Name string//字段名Type Type//字段类型Tag StructTag     //Tag 的类型为structTag,实际上它是一个string类型的别名//Tag
}

key会指定反射的解析方式,如下: json(JSON标签) 、orm(Beego标签)、gorm(GORM标签)、bson(MongoDB标签)、form(表单标签)、binding(表单验证标签)、yaml

Tag的意义

Go语言的反射特性可以动态地给结构体成员赋值,正是因为有Tag,在赋值前可以使用Tag来决定赋值的动作。
比如,官方的encoding/json包可以将一个JSON 数据“Unmarshal”进一个结构体,此过程中就使用了 Tag。该包定义了一些Tag 规则,只要参考该规则设置tag 就可以将不同的JSON数据转换成结构体。

在Golang中,命名都是推荐用驼峰方式,并且在首字母大小写有特殊的语法含义:包外无法引用。但是由于经常需要和其它的系统进行数据交互,例如转成json格式,存储到mongodb啊等等。这个时候如果用属性名来作为键值可能不一定会符合项目要求。
而通过Tag,我们可以在转换成其它格式的时候,使用其中定义的字段作为键值。

type User struct {UserId int `json:"user_id"`UserName string `json:"user_name"`
}
func main()  {u := &User{UserId: 1, UserName: "张三"}j, _ := json.Marshal(u)fmt.Println(string(j))
}//{"user_id":1,"user_name":"张三"}

Tag约定

结构体标签由一个或多个键值对组成。键与值使用冒号分隔,值用双引号括起来。键值对之间使用一个空格分隔,具体的格式如下:

`key1:"value1" key2:"value2" key3:"value3"...`  // 键值对用空格分隔

Tag 本身是一个字符串,单从语义上讲,任意的字符串都是合法的。但它有一个约定的格式,那就是字符串由key:"value"组成。
key 必须是非空字符串,字符串不能包含控制字符、空格、引号、冒号;
value 以双引号标记的字符串。
注意: key和 value之间使用冒号分隔,冒号前后不能有空格,多个key : "value"之间由空格分开。

Kind string `json:"kind, omitempty" protobuf:"bytes,1, opt, name=kind"`

key一般表示用途,比如.json表示用于控制结构体类型与JSON格式数据之间的转换,protobuf表示用于控制序列化和反序列化。value一般表示控制指令,具体控制指令由不同的库指定。

获取Tag值

package mainimport ("fmt""reflect"
)type Food struct {Apple string `fruit:"apple"`Tomato string `vegetable:"tomato"`
}func main() {t := reflect.TypeOf(Food{})f, _ := t.FieldByName("Apple")fmt.Println(f.Tag)// Tag.Lookupv, ok := f.Tag.Lookup("fruit")fmt.Printf("%s, %t\n", v, ok)// Tag.Getv = f.Tag.Get("fruit")fmt.Println(v)
}

运行结果

fruit:"apple"
apple, true
apple

json Tag

type Student struct {ID   int     `json:"-"`            // 该字段不进行序列化Name string  `json:name,omitempy`  // 如果为类型零值或空值,序列化时忽略该字段Age  int     `json:age,string`     // 重新指定字段类型,支持string、number、boolen
}

https://studygolang.com/static/pkgdoc/pkg/encoding_json.htm

json编码

type User struct {ID   int `json:"id"`  // 编码后的字段名为 idName string           // 编码后的字段名为 自定义成员名 Nameage  int              // 未导出字段不能编码
}

在 Go 语言中,如果一个结构体的字段名首字母是大写,那么它就是一个 “导出字段”(Exported Field),意味着它可以被外部的包访问和操作。反之,如果一个字段名首字母是小写,那么它就是一个 “未导出字段”(Unexported Field),只能在当前的包内部被访问和操作。
在进行 JSON 编码(encoding)或解码(decoding)时,只有结构体的导出字段才会被处理。

gorm

GORM Tag名大小写不敏感,建议使用camelCase风格,多个标签定义用分号(;)分隔
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

// 新闻模型
type News struct {ModelTitle   string   `gorm:"column:title;type:string;not null,default:''"`Content Content  `gorm:"foreignKey:NewsId" json:"content"` //指定外键
}
// AUTO_INCREMENT 不生效
Id  uint64 `gorm:"column:id;primaryKey;type:bigint(20);autoIncrement;comment:'主键'"`
// AUTO_INCREMENT 不生效
Id  uint64 `gorm:"column:id;type:bigint(20);autoIncrement;comment:'主键'"`
// AUTO_INCREMENT 生效 gorm会自动根据字段类型设置数据库字段类型并设置为主键
Id  uint64 `gorm:"column:id;autoIncrement;comment:'主键'"` //写成AUTO_INCREMENT也可以

yaml inline

在 Go 语言结构体标签(struct tags)中,yaml:",inline" 是一种特殊的标识符,表示“内联”,也就是嵌入。
这个标识符的作用主要有两层含义:

  • 对于 Go 语言的结构体字段(Struct Fields)本身,如果这个字段的类型是另一个结构体,那么在编组和解组这个结构体的时候,它的字段会被当作是外层结构体的字段来处理。
  • 对于解析 YAML 文件时,如果一个字段被标记为 inline,那么在这个 YAML 文件被解析成 Go 语言结构体的时候,这个字段将会把它的子节点看作是自己的直接字段。
type Person struct {Name string `yaml:"name"`Age  int    `yaml:"age"`
}type Employee struct {Person `yaml:",inline"`Job    string `yaml:"job"`
}

当你在解析如下的 YAML 时:

yaml
name: Mike
age: 30
job: engineer

那么,这个 YAML 将会被解析成如下的 Go 语言结构体:

Employee{Person: Person{Name: "Mike",Age:  30,},Job: "engineer",
}

可以看到,虽然 YAML 文件中并没有 Person 这一层,但是由于 Person 被标记为 inline,Name 和 Age 字段就像是 Employee 的直接字段一样被处理了。

xml


func ExampleMarshalIndent() {type Address struct {City, State string}type Person struct {XMLName   xml.Name `xml:"person"`Id        int      `xml:"id,attr"`FirstName string   `xml:"name>first"`LastName  string   `xml:"name>last"`Age       int      `xml:"age"`Height    float32  `xml:"height,omitempty"`Married   boolAddressComment string `xml:",comment"`}v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42}v.Comment = " Need more details. "v.Address = Address{"Hanga Roa", "Easter Island"}output, err := xml.MarshalIndent(v, "  ", "    ")if err != nil {fmt.Printf("error: %v\n", err)}os.Stdout.Write(output)// Output://   <person id="13">//       <name>//           <first>John</first>//           <last>Doe</last>//       </name>//       <age>42</age>//       <Married>false</Married>//       <City>Hanga Roa</City>//       <State>Easter Island</State>//       <!-- Need more details. -->//   </person>
}func ExampleEncoder() {type Address struct {City, State string}type Person struct {XMLName   xml.Name `xml:"person"`Id        int      `xml:"id,attr"`FirstName string   `xml:"name>first"`LastName  string   `xml:"name>last"`Age       int      `xml:"age"`Height    float32  `xml:"height,omitempty"`Married   boolAddressComment string `xml:",comment"`}v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42}v.Comment = " Need more details. "v.Address = Address{"Hanga Roa", "Easter Island"}enc := xml.NewEncoder(os.Stdout)enc.Indent("  ", "    ")if err := enc.Encode(v); err != nil {fmt.Printf("error: %v\n", err)}// Output://   <person id="13">//       <name>//           <first>John</first>//           <last>Doe</last>//       </name>//       <age>42</age>//       <Married>false</Married>//       <City>Hanga Roa</City>//       <State>Easter Island</State>//       <!-- Need more details. -->//   </person>
}// This example demonstrates unmarshaling an XML excerpt into a value with
// some preset fields. Note that the Phone field isn't modified and that
// the XML <Company> element is ignored. Also, the Groups field is assigned
// considering the element path provided in its tag.
func ExampleUnmarshal() {type Email struct {Where string `xml:"where,attr"`Addr  string}type Address struct {City, State string}type Result struct {XMLName xml.Name `xml:"Person"`Name    string   `xml:"FullName"`Phone   stringEmail   []EmailGroups  []string `xml:"Group>Value"`Address}v := Result{Name: "none", Phone: "none"}data := `<Person><FullName>Grace R. Emlin</FullName><Company>Example Inc.</Company><Email where="home"><Addr>gre@example.com</Addr></Email><Email where='work'><Addr>gre@work.com</Addr></Email><Group><Value>Friends</Value><Value>Squash</Value></Group><City>Hanga Roa</City><State>Easter Island</State></Person>`err := xml.Unmarshal([]byte(data), &v)if err != nil {fmt.Printf("error: %v", err)return}fmt.Printf("XMLName: %#v\n", v.XMLName)fmt.Printf("Name: %q\n", v.Name)fmt.Printf("Phone: %q\n", v.Phone)fmt.Printf("Email: %v\n", v.Email)fmt.Printf("Groups: %v\n", v.Groups)fmt.Printf("Address: %v\n", v.Address)// Output:// XMLName: xml.Name{Space:"", Local:"Person"}// Name: "Grace R. Emlin"// Phone: "none"// Email: [{home gre@example.com} {work gre@work.com}]// Groups: [Friends Squash]// Address: {Hanga Roa Easter Island}
}

Go vet

vet 是 golang 中自带的静态分析工具,可以让我们检查出 package 或者源码文件中一些隐含的错误

Go 编译器没有强制执行传统的 struct 标签格式,但是 vet 就是这样做的,所以值得使用它,例如作为 CI 管道的一部分。

type T struct {f string "one two three"
}
func main() {}> Go vet tags.go
tags.go:4: struct field tag `one two three` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair
//在 Go 语言中,当你使用结构体标签(struct tag)去描述一个结构体中的字段时,其格式必须严格遵守 "键:值"("key:value")的形式。type T struct {Name  string "json:Name"
}
$ go vet
# command-line-arguments
./main.go:8: struct field tag "json:Name" not compatible with reflect.StructTag.Get: bad syntax for struct tag value//JSON 标签的字段名 Name 是以大写字符开始的,这不符合 Go 语言的标准

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/778613.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GeoTrust SSL证书有什么优势?

GeoTrust SSL证书具备以下显著优势&#xff1a; 1. 市场占有率比较高&#xff1a;GeoTrust作为知名的SSL证书供应商&#xff0c;拥有广泛的市场接受度和高占有率&#xff0c;表明其产品受到众多企业和网站的信任和采用。 2. 品牌信誉与信任标识&#xff1a;在高安全性浏览器中&…

Unity3d使用Jenkins自动化打包(Windows)(一)

文章目录 前言一、安装JDK二、安装Jenkins三、Jenkins插件安装和使用基础操作 实战一基础操作 实战二 四、离线安装总结 前言 本篇旨在介绍基础的安装和操作流程&#xff0c;只需完成一次即可。后面的篇章将深入探讨如何利用Jenkins为Unity项目进行打包。 一、安装JDK 1、进入…

在word中显示Euclid Math One公式的问题及解决(latex公式,无需插件)

问题&#xff1a;想要在word中显示形如latex中的花体字母 网上大多解决办法是安装Euclid Math One。安装后发现单独的符号插入可行&#xff0c;但是公式中选择该字体时依然显示默认字体。 解决办法&#xff1a;插入公式后&#xff0c;勾选左上角的latex 在公式块中键入latex代码…

Go语言爬虫实战(线程池)

Go语言爬虫实战 目标 利用go语言爬取指定网站的图片。实现爬取网站任意页面所有所需的图片。实现使用go语言线程池开启多个线程爬取图片内容。最后实现创建多个文件夹存储图片。 爬取网站图片 步骤 对指定URL发去GET请求&#xff0c;获取对应的响应。 resp, err : http.Get(…

【JavaWeb】Day24.Web入门——HTTP协议(一)

HTTP协议——概述 1.介绍 HTTP&#xff1a;Hyper Text Transfer Protocol(超文本传输协议)&#xff0c;规定了浏览器与服务器之间数据传输的规则。 http是互联网上应用最为广泛的一种网络协议http协议要求&#xff1a;浏览器在向服务器发送请求数据时&#xff0c;或是服务器在…

AI写作的力量:让你的文章焕发生机

在当今数字化时代&#xff0c;内容创作变得越来越重要。无论是博客文章、广告文案还是社交媒体更新&#xff0c;优质的文本都能吸引读者的注意力并传达信息。然而&#xff0c;创作过程并不总是轻松的&#xff0c;尤其是当我们面临灵感枯竭或时间紧迫的挑战时。这就是AI写作的力…

网站为什么要选择使用安全加速SCDN?

安全加速SCDN&#xff08;安全内容交付网络&#xff09;是一种网络加速服务&#xff0c;旨在提高网站和应用程序的性能和安全性。它使用专门的技术和基础设施来加速内容传输并保护网站免受网络攻击。 安全加速SCDN可以通过内容缓存、快速传输和动态路由技术来加速网站和应用程…

安卓调试桥ADB

Logcat 命令行工具 | Android Studio | Android Developers 什么是ADB ADB 全称为 Android Debug Bridge &#xff0c;是 Android SDK &#xff08;安卓的开发工具&#xff09;中的一个工具&#xff0c;起到调试桥的作用&#xff0c;是一个 客户端 - 服务器端程序 。其中 …

【Linux】开始掌握进程控制吧

送给大家一句话&#xff1a; 我并不期待人生可以一直过得很顺利&#xff0c;但我希望碰到人生难关的时候&#xff0c;自己可以是它的对手。—— 加缪 开始学习进程控制 1 前言2 进程创建2.1 fork函数初识2.2 fork函数返回值2.3 写时拷贝2.4 fork常规用法2.5 fork调用失败的原因…

3月23日笔记

广播域与泛洪范围是相同的 广播&#xff1a;在同一个泛洪范围内&#xff0c;强迫交换机泛洪&#xff08;主动&#xff09; 泛洪&#xff08;被动&#xff09; ARP的工作原理&#xff1a;ARP先通过广播发送请求包&#xff0c;所有收到该广播包的设备都会将其中的源IP和源MAC相…

Oracle存数字精度问题number、binary_double、binary_float类型

--表1 score是number(10,5)类型 create table TEST1 (score number(10,5) ); --表2 score是binary_double类型 create table TEST2 (score binary_double ); --表3 score是binary_float类型 create table TEST3 (score binary_float );实验一&#xff1a;分别往三张表插入 小数…

OpenCV 形态学处理函数

四、形态学处理&#xff08;膨胀&#xff0c;腐蚀&#xff0c;开闭运算&#xff09;_getstructuringelement()函数作用-CSDN博客 数字图像处理(c opencv)&#xff1a;形态学图像处理-morphologyEx函数实现腐蚀膨胀、开闭运算、击中-击不中变换、形态学梯度、顶帽黑帽变换 - 知乎…

JAVA面试八股文之集合

JAVA集合相关 集合&#xff1f;说一说Java提供的常见集合&#xff1f;hashmap的key可以为null嘛&#xff1f;hashMap线程是否安全, 如果不安全, 如何解决&#xff1f;HashSet和TreeSet&#xff1f;ArrayList底层是如何实现的&#xff1f;ArrayList listnew ArrayList(10)中的li…

Day24:私信列表、私信详情、发送私信

测试用户&#xff1a;用户名aaa 密码aaa 查询当前用户的会话列表&#xff1b;每个会话只显示一条最新的私信&#xff1b;支持分页显示。 首先看下表结构&#xff1a; conversation_id: 用from_id和to_id拼接&#xff0c;小的放前面去&#xff08;因为两个人的对话应该在一个会…

Siemens S7-1500TCPU 运动机构系统功能简介

目录 引言&#xff1a; 1.0 术语定义 2.0 基本知识 2.1 运动系统工艺对象 2.2 坐标系与标架 3.0 运动机构系统类型 3.1 直角坐标型 3.2 轮腿型 3.3 平面关节型 3.4 关节型 3.5 并联型 3.6 圆柱坐标型 3.7 三轴型 4.0 运动系统的运动 4.1 运动类型 4.1.1 线性运动…

新手体验OceanBase社区版V4.2:离线部署单节点集群

本文源自OceanBase用户的分享 先简单总结如下&#xff1a; 1.本文适合初学者体验OceanBase社区版 v4.2.2 2.仅需准备一台配置为2C/8G的Linux虚拟机 3.通过离线方式安装&#xff0c;以便更直观地了解安装过程 一、Linux系统准备 在宿主机(即你的windows PC电脑)上安装vbox软…

【JavaEE初阶系列】——多线程案例四——线程池

目录 &#x1f6a9;什么是线程池 &#x1f388;从池子中取效率大于新创建线程效率(why) &#x1f6a9;标准库中的线程池 &#x1f388;为什么调用方法而不是直接创建对象 &#x1f388;工厂类里的方法 &#x1f4dd;newCachedThreadPool() &#x1f4dd;newFixedThread…

【微服务】Nacos(配置中心)

文章目录 1.AP和CP1.基本介绍2.说明 2.Nacos配置中心实例1.架构图2.在Nacos Server加入配置1.配置列表&#xff0c;加号2.加入配置3.点击发布&#xff0c;然后返回4.还可以编辑 3. 创建 Nacos 配置客户端模块获取配置中心信息1.创建子模块 e-commerce-nacos-config-client50002…

Matlab之求直角坐标系下两直线的交点坐标

目的&#xff1a;在直角坐标系下&#xff0c;求两个直线的交点坐标 一、函数的参数说明 输入参数&#xff1a; PointA&#xff1a;直线A上的点坐标&#xff1b; AngleA&#xff1a;直线A的倾斜角&#xff0c;单位度&#xff1b; PointB&#xff1a;直线B上的点坐标&#xf…

LeetCode - 股票平滑下跌阶段的数目(分组循环)

2110. 股票平滑下跌阶段的数目 当数组中的数字满足这个prices[i] 1 prices[i - 1]条件之后&#xff0c;就是平滑下降的阶段&#xff0c;也就是将数组中连续的数字进行一个分组。每次计算一个分组即可。 class Solution { public:long long getDescentPeriods(vector<int&…