大家好,我是明哥。

由于某些不可抗力,之前该专栏的所有内容都被删除了。因此之后的一段时间内,我会重新发布这些文章,先给已经看过的关注者提个醒。


本文原文:http://golang.iswbm.com

Github:http://github.com/iswbm/GolangCodingTime

1. 抛砖引玉:什么是 Tag?

正常情况下,你定义的结构体是这样子的,每个字段都由名字和字段类型组成

type Person struct {Name string Age  int   Addr string
}

也有例外,就像下面这样子,字段上还可以额外再加一个属性,用反引号(Esc键下面的那个键)包含的字符串,称之为 Tag,也就是标签。

type Person struct {Name string `json:"name"`Age  int    `json:"age"`Addr string `json:"addr,omitempty"`
}

那么这个标签有什么用呢?

这边先以 encoding/json 库的用法抛砖引玉,看一下它能起到什么样的效果。

package mainimport ("encoding/json""fmt"
)type Person struct {Name string `json:"name"`Age  int    `json:"age"`Addr string `json:"addr,omitempty"`
}func main() {p1 := Person{Name: "Jack",Age:  22,}data1, err := json.Marshal(p1)if err != nil {panic(err)}// p1 没有 Addr,就不会打印了fmt.Printf("%sn", data1)// ================p2 := Person{Name: "Jack",Age:  22,Addr: "China",}data2, err := json.Marshal(p2)if err != nil {panic(err)}// p2 则会打印所有fmt.Printf("%sn", data2)
}

由于 Person 结构体里的 Addr 字段有 omitempty 属性,因此 encoding/json 在将对象转化 json 字符串时,只要发现对象里的 Addr 为 false, 0, 空指针,空接口,空数组,空切片,空映射,空字符串中的一种,就会被忽略。

因此运行后,输出的结果如下

$ go run demo.go
{"name":"Jack","age":22}
{"name":"Jack","age":22,"addr":"China"}

2. 不懂就问:如何定义获取 Tag ?

Tag 由反引号包含,由一对或几对的键值对组成,通过空格来分割键值。格式如下

`key01:"value01" key02:"value02" key03:"value03"`

定义完后,如何从结构体中,取出 Tag 呢?

答案就是,我们上一节学过的 "反射"。

获取 Tag 可以分为三个步骤:

  1. 获取字段 field
  1. 获取标签 tag
  1. 获取键值对 key:value

演示如下

// 三种获取 field
field := reflect.TypeOf(obj).FieldByName("Name")
field := reflect.ValueOf(obj).Type().Field(i)  // i 表示第几个字段
field := reflect.ValueOf(&obj).Elem().Type().Field(i)  // i 表示第几个字段// 获取 Tag
tag := field.Tag // 获取键值对
labelValue := tag.Get("label")
labelValue,ok := tag.Lookup("label")

获取键值对,有Get 和 Lookup 两种方法,但其实 Get 只是对 Lookup 函数的简单封装而已,当没有获取到对应 tag 的内容,会返回空字符串。

func (tag StructTag) Get(key string) string {v, _ := tag.Lookup(key)return v
}

空 Tag 和不设置 Tag 效果是一样的

package mainimport ("fmt""reflect"
)type Person struct {Name string ``Age string
}
func main() {p := reflect.TypeOf(Person{})name, _ := p.FieldByName("Name")fmt.Printf("%qn", name.Tag) //输出 ""age, _ := p.FieldByName("Age")fmt.Printf("%qn", age.Tag) // 输出 ""
}

3. 实战一下:利用 Tag 搞点事情?

学会了如何定义 tag 和 获取 tag,可以试着利用 tag 来做一些事情,来练习一下。

这边我举个例子吧。

如果我想实现一个函数(就叫 Print 吧),在打印 person 对象时,能够美化输出

type Person struct {Name        string Age         int    Gender      string
}person := Person{Name:        "MING",Age:         29,
}Print(person)

就像下面这样,key 和 value 之间有个 is:,如果没有指定 Gender 的值,那么显示为unknown(未知)。

Name is: MING
Age is: 29
Gender is: unknown

那该怎么做呢?

先改造下 Person 结构体,给每个字段加上 tag 标签,三个字段的tag 都有 label 属性,而 Gender 多了一个 default 属性,意在指定默认值。

type Person struct {Name        string `label:"Name is: "`Age         int    `label:"Age is: "`Gender      string `label:"Gender is: " default:"unknown"`
}

然后来写一下这个 Print 函数

func Print(obj interface{}) error {// 取 Valuev := reflect.ValueOf(obj)// 解析字段for i := 0; i < v.NumField(); i++ {// 取tagfield := v.Type().Field(i)tag := field.Tag// 解析label 和 defaultlabel := tag.Get("label")defaultValue := tag.Get("default")value := fmt.Sprintf("%v", v.Field(i))if value == "" {// 如果没有指定值,则用默认值替代value = defaultValue}fmt.Println(label + value)}return nil
}

最后执行一下,看了下输出,符合我们的预期:

$ go run demo.go
Name is: MING
Age is: 29
Gender is: unknown

到此,我们就把 Tag 的用法介绍完了。


好了,今天的文章就到这里了。

若今天的分享对你有帮助,不如点个赞,支持一下?

golang获取结构体中的tag_26. Go 语言中结构体的 Tag 用法相关推荐

  1. Linux结构体变量报错,C语言中的结构体

    用户自己建立自己的结构体类型 1.  定义和使用结构体变量 (1).结构体的定义 C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体. (2).声明一个结构体类型的一般形式为: ...

  2. python语言的注释语句引导符不包括什么_以下选项中,哪一个是Python语言中代码注释使用的符号?________...

    [单选题]关于 Python 语句 P = –P,以下选项中描述正确的是________ [多选题]Python的数字类型包括( ) [多选题]Python中的注释符有哪几种?( ) [判断题]已知 ...

  3. 结构体前面加星号_C语言中带星号的类型指针有哪些特性

    C语言中带星号的类型指针有哪些特性 指针是什么?很多人说,指针就是地址,那这么说的人肯定是对指针有所了解,他们这么说也不能说全错,我只能在这里说:"他们并没有真正学会指针,如果想学好指针,请 ...

  4. c语言结构体成员变量私有化,C语言中结构体变量私有化详解

    C语言中结构体变量私有化详解 背景介绍 操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚 ...

  5. c语言的结构体指针的引用,C语言中的指针、引用、数组、结构体

    指针.引用和取值 什么是指针?什么是内存地址?什么叫做指针的取值?指针是一个存储计算机内存地址的变量.在这份教程里"引用"表示计算机内存地址.从指针指向的内存读取数据称作指针的取值 ...

  6. c++ 结构体初始化_单片机C语言 - 基于结构体的面向对象编程技巧

    单片机C语言 - 基于结构体的面向对象编程技巧 一.面向对象 面向对象是软件开发方法,是相对于面向过程来讲的.通过把数据与方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式 ...

  7. c语言中用于获取字符串长度的函数是,C语言中求字符串长度的函数的几种实现方法...

    C语言中求字符串长度的函数的几种实现方法 1.最常用的方法是创建一个计数器,判断是否遇到'\0',不是'\0'指针就往后加一. int my_strlen(const char *str) { ass ...

  8. c语言程序开发中连接是,C语言中等待socket连接和对socket定位的方法

    C语言listen()函数:等待连接头文件: #include 定义函数: int listen(int s,int backlog); 函数说明:listen()用来等待参数s 的socket 连线 ...

  9. r语言 rgl 强制过程中_一个R语言中操纵矢量空间数据的标准化工具—sf

    ​注: 本文是R语言sf包的核心开发者和维护者--来自德国明斯特大学的地理信息学教授:Edzer Pebesma 的一篇关于sf包的简介,发表于2018年7月的R语言期刊,主要讲述了sf的定位.功能. ...

最新文章

  1. 【Linux 内核】CFS 调度器 ② ( CFS 调度器 “ 权重 “ 概念 | CFS 调度器调度实例 | 计算进程 “ 实际运行时间 “ )
  2. 考研常识:研究生单独考试是什么意思?
  3. python常用_Python常用小技巧
  4. 推荐:周志华《机器学习》西瓜书精炼版笔记来了!
  5. mac端addr2line的NDK位置和使用
  6. css --- 选择器
  7. 前端学习(2954):vue文件的三大组成部分
  8. Springboot java -jar 提示没没有主清单属性
  9. 用DotNetOpenAuth实现基于OAuth 2.0的web api授权 (一)Getting Start
  10. 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
  11. word-break: break-all与word-wrap:break-word的区别
  12. 高德地图POI数据爬取
  13. 什么是PY平台?Python平台用途及安装的详细方法
  14. vector begin()用法
  15. c语言单片机仿真keil,如何在keil中仿真stm32单片机
  16. 安大计算机学院ACM,安徽大学计算机科学与技术学院硕士生导师:张磊
  17. ios11非越狱如何安装ipa
  18. 使用 VMware 16 RHEL7.7 虚拟机静默安装 Oracle 19c RAC
  19. stm8l051 halt之后外部中断唤醒问题
  20. js 函数闭包内部返回函数体调用方法难点解答

热门文章

  1. Java实现Google第三方登录
  2. 算法训练营05-二叉树
  3. 操作系统(2) -- 进程管理
  4. 测试点解析:1049 数列的片段和_12行代码AC
  5. 如何使 子页面顶部栏 覆盖app.json中的顶部栏
  6. (~解题报告~)L1-017 到底有多二 (15分)(16行代码AC)
  7. 最全!最完整的设计词法分析程序的代码!!!
  8. C++STL容器,你真的会用了吗?——插入、删除、遍历和查找操作性能对比——删除(精简易懂版,句句干货)
  9. 三位整数两位小数掩码_小数点造句_造句大全
  10. SQL语句的添加、删除、修改多种方法