【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 main

import (
	"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.Lookup
	v, ok := f.Tag.Lookup("fruit")
	fmt.Printf("%s, %t\n", v, ok)

	// Tag.Get
	v = 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"`  // 编码后的字段名为 id
    Name string           // 编码后的字段名为 自定义成员名 Name
    age  int              // 未导出字段不能编码
}

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

gorm

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

在这里插入图片描述

在这里插入图片描述

// 新闻模型
type News struct {
    Model
    Title   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   bool
		Address
		Comment 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   bool
		Address
		Comment 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   string
		Email   []Email
		Groups  []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.mfbz.cn/a/499386.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JavaSE】java刷题——基础语法熟练应用

前言 通过本篇题目&#xff0c;可以让初学Java的小伙伴们更加熟练Java的基础语法~ 欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 题1&#xff1a;数字9 出现的次数 题述&#xff1a;编写程序数一下 1到 100 的所有整数中…

四平方和定理

四平方和定理&#xff1a;任意一个正整数都可以被表示为至多四个正整数的平方和。 更强的结论&#xff1a;当且仅当时&#xff0c;n可以被表示为至多三个正整数的平方和&#xff0c;因此&#xff0c;当时&#xff0c;n只能被表示为四个正整数的平方和。 如果 &#xff0c;这个时…

Leetcode - 周赛390

目录 一&#xff0c;3090. 每个字符最多出现两次的最长子字符串 二&#xff0c;3091. 执行操作使数据元素之和大于等于 K 三&#xff0c;3092. 最高频率的 ID 四&#xff0c;3093. 最长公共后缀查询 一&#xff0c;3090. 每个字符最多出现两次的最长子字符串 本题是一道标准…

JavaEE企业开发新技术4

2.16 模拟Spring IOC容器功能-1 2.17 模拟Spring IOC容器功能-2 什么是IOC&#xff1f; 控制反转&#xff0c;把对象创建和对象之间的调用过程交给Spring框架进行管理使用IOC的目的&#xff1a;为了耦合度降低 解释&#xff1a; 模仿 IOC容器的功能&#xff0c;我们利用 Map…

LeetCode 206.反转链表

给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1] 示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1] 示例 3&#xff1a; …

这款基于Vue的大数据可视化平台,你绝对值得拥有

这款基于Vue的大数据可视化平台&#xff0c;你绝对值得拥有 一、项目介绍二、相关技术栈三、运行步骤四、项目演示五、总结 大家好&#xff0c;这里是程序猿代码之路。今天主要给大家介绍一款基于Vue的可视化数据大屏。在数字化转型的浪潮中&#xff0c;大数据的可视化展示变得…

【Win】使用PowerShell和Webhooks轻松发送消息至Microsoft Teams

Microsoft Teams是一款由微软开发的团队协作和通讯工具。如果您对这个名字还不太熟悉&#xff0c;那么现在就是一个了解它的好时机。微软将Teams定位为其之前Skype for Business解决方案的继任者&#xff0c;并且它也提供了与其他基于频道的通讯应用程序&#xff08;例如Slack、…

关于Devc++调试的问题以及解决STL变量无法查看

目前Devc的调试主要有以下几点&#xff1a; 1.调试不能直接查看stl变量&#xff0c;会卡死不动 2.目前单步进入只能用鼠标键按 3.若想按下一步进入函数体内&#xff0c;要在函数体内打上断点才行 4.调试到return 0 ;上一句就停了&#xff0c;不会结束程序 5.目前F2跳至断点…

30-3 越权漏洞 - 水平越权(横向越权)

环境准备:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 一、定义 攻击者可以访问和操作与其拥有同级权限的用户资源。 示例: 学生A在教务系统上正常只能修改自己的作业内容,但由于不合理的权限校验规则等原因,学生A可以修改学生B的内…

文件夹中的文件如何全部加密

数字化时代&#xff0c;信息安全已成为我们日常生活中不可或缺的一部分。 而数据泄露和非法访问的风险却日益增加。 对于个人和企业而言&#xff0c;如何保护文件夹中的文件安全&#xff0c;防止数据被非法获取或篡改&#xff0c;是企业必须要重视的问题。 文件进行加密是一项…

【考研数学】听完课,汤家凤《1800题》基础练习都做不动?!

入门题基本都会&#xff0c;说明知识点学的没问题 但是一到基础就歇菜&#xff0c;说明题目综合度以上来&#xff0c;就没有思路&#xff0c;做不出来。 这种问题我在考研初期也遇到过&#xff0c;不要慌&#xff0c;这些都能够通过后期的练习弥补上来。 学习的过程其实很奇…

on-my-zsh 命令自动补全插件 zsh-autosuggestions 安装和配置

首先 Oh My Zsh 是什么? Oh My Zsh 是一款社区驱动的命令行工具&#xff0c;正如它的主页上说的&#xff0c;Oh My Zsh 是一种生活方式。它基于 zsh 命令行&#xff0c;提供了主题配置&#xff0c;插件机制&#xff0c;已经内置的便捷操作。给我们一种全新的方式使用命令行。…

.msi文件的安装

这里写目录标题 1.winR--》services.msc2.启动Windows Installer3.winR --》cmd4.输入命令&#xff0c;安装 1.winR–》services.msc 2.启动Windows Installer 3.winR --》cmd 4.输入命令&#xff0c;安装 msiexec/package 文件路径文件名 package和文件路径之间有个空格&#…

Unity颗粒血条的实现(原创,参考用)

1.创建3个静态物体摆好位置&#xff0c;并将其图层设为UI 2.编写一个脚本 using System.Collections; using System.Collections.Generic; using UnityEngine;public class xt : MonoBehaviour {public GameObject xt1;public GameObject xt2;public GameObject xt3;int x 1;…

scGRN:人与鼠的GRN平台

基因调控网络GRN是包含转录因子TFs与其下游靶基因之间的调控相互作用的可解释图模型。了解GRN的拓扑结构和动力学是解释疾病病因机制和将相应发现转化为新疗法的基础。单细胞多组学技术的最新进展促使从单细胞转录组学和表观基因组学数据中以前所未有的分辨率推断GRN。在这里&a…

T31ZC 君正T31 快启简化版 QFN封装

T31智能视频处理器凝聚了君正多项技术精华&#xff0c;继承了丰富的视频应用经验&#xff0c;拥有较强的CPU计算性能&#xff0c; 专业的成像能力&#xff0c;优秀的编码品质&#xff0c;丰富的差异化扩展&#xff0c;良好的成本控制和低功耗基因&#xff0c;搭配整合好的丰 富…

离线Linux/openEuler服务器指定本地yum仓库

1、前提准备一个预装坏境比较完整的linux镜像文件&#xff0c;本文服务器使用的是openEuler 官网&#xff1a;openEuler下载 | 欧拉系统ISO镜像 | openEuler社区官网 2、上传镜像文件至服务器 如果是集群服务器&#xff0c;上传其中一台服务器之后&#xff0c;使用scp指令将镜…

uniapp开发App——登陆流程 判断是否登陆,是,进入首页,否,跳转到登录页

一、登陆流程 文字描述&#xff1a;用户进入App&#xff0c;之后就是判断该App是否有用户登陆过&#xff0c;如果有&#xff0c;直接进入首页&#xff0c;否则跳转到登陆页&#xff0c;登陆成功后&#xff0c;进入首页。 流程图如下&#xff1a; 二、在uniapp项目中代码实现 实…

海外媒体发稿:3种媒体宣发套餐内容推广方法

现如今&#xff0c;伴随着信息技术的不断进步和推广&#xff0c;新闻媒体宣发变成企业品牌推广的重要手段之一。为了方便让新闻信息新闻资讯传递给目标群体&#xff0c;公司一般会选择不同的套餐内容和推广方法。下面我们就详细介绍3种新闻资讯新闻媒体宣发套餐内容推广方法。 …

【八大排序】一篇文章搞定所有排序

文章目录 1.排序的概念2.常见排序算法的实现2.1 插入排序2.1.1直接插入排序2.1.2希尔排序 2.2选择排序2.2.1直接选择排序:2.2.2堆排序 2.3交换排序2.3.1冒泡排序2.3.2快速排序Hoare法前后指针法挖坑法非递归版本 2.4归并排序递归版本非递归版本 2.5计数排序3.排序的比较 1.排序…