Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
go开源项目镜像
GolangCodingTime
提交
a194210c
G
GolangCodingTime
项目概览
go开源项目镜像
/
GolangCodingTime
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
GolangCodingTime
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
a194210c
编写于
7月 22, 2020
作者:
写代码的明哥
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Update: make rst
上级
6dd810f6
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
103 addition
and
35 deletion
+103
-35
source/c02/c02_10.md
source/c02/c02_10.md
+9
-9
source/c02/c02_10.rst
source/c02/c02_10.rst
+94
-26
未找到文件。
source/c02/c02_10.md
浏览文件 @
a194210c
# 2.10 反引号的妙用:结构体里的 Tag 用法
# 2.10 反引号的妙用:结构体里的 Tag 用法
![](
http://image.iswbm.com/20200607145423.png
)
## 1. 抛砖引玉:什么是 Tag?
## 1. 抛砖引玉:什么是 Tag?
正常情况下,你定义的结构体是这样子的,每个字段都由名字和字段类型组成
正常情况下,你定义的结构体是这样子的,每个字段都由名字和字段类型组成
...
@@ -87,9 +89,9 @@ $ go run demo.go
...
@@ -87,9 +89,9 @@ $ go run demo.go
Tag 由反引号包含,由一对或几对的键值对组成,通过空格来分割键值。格式如下
Tag 由反引号包含,由一对或几对的键值对组成,通过空格来分割键值。格式如下
```
```
`key01:"value01" key02:"value02" key03:"value03"`
`key01:"value01" key02:"value02" key03:"value03"`
```
```
定义完后,如何从结构体中,取出 Tag 呢?
定义完后,如何从结构体中,取出 Tag 呢?
...
@@ -103,7 +105,7 @@ Tag 由反引号包含,由一对或几对的键值对组成,通过空格来
...
@@ -103,7 +105,7 @@ Tag 由反引号包含,由一对或几对的键值对组成,通过空格来
演示如下
演示如下
```
go
```
go
// 三种获取 field
// 三种获取 field
field
:=
reflect
.
TypeOf
(
obj
)
.
FieldByName
(
"Name"
)
field
:=
reflect
.
TypeOf
(
obj
)
.
FieldByName
(
"Name"
)
field
:=
reflect
.
ValueOf
(
obj
)
.
Type
()
.
Field
(
i
)
// i 表示第几个字段
field
:=
reflect
.
ValueOf
(
obj
)
.
Type
()
.
Field
(
i
)
// i 表示第几个字段
...
@@ -115,16 +117,16 @@ tag := field.Tag
...
@@ -115,16 +117,16 @@ tag := field.Tag
// 获取键值对
// 获取键值对
labelValue
:=
tag
.
Get
(
"label"
)
labelValue
:=
tag
.
Get
(
"label"
)
labelValue
,
ok
:=
tag
.
Lookup
(
"label"
)
labelValue
,
ok
:=
tag
.
Lookup
(
"label"
)
```
```
获取键值对,有Get 和 Lookup 两种方法,但其实 Get 只是对 Lookup 函数的简单封装而已,当没有获取到对应 tag 的内容,会返回空字符串。
获取键值对,有Get 和 Lookup 两种方法,但其实 Get 只是对 Lookup 函数的简单封装而已,当没有获取到对应 tag 的内容,会返回空字符串。
```
go
```
go
func
(
tag
StructTag
)
Get
(
key
string
)
string
{
func
(
tag
StructTag
)
Get
(
key
string
)
string
{
v
,
_
:=
tag
.
Lookup
(
key
)
v
,
_
:=
tag
.
Lookup
(
key
)
return
v
return
v
}
}
```
```
空 Tag 和不设置 Tag 效果是一样的
空 Tag 和不设置 Tag 效果是一样的
...
@@ -177,7 +179,7 @@ Print(person)
...
@@ -177,7 +179,7 @@ Print(person)
就像下面这样,key 和 value 之间有个
`is:`
,如果没有指定 Gender 的值,那么显示为unknown(未知)。
就像下面这样,key 和 value 之间有个
`is:`
,如果没有指定 Gender 的值,那么显示为unknown(未知)。
```
shell
```
shell
Person Name
: MING
Name is
: MING
Age is: 29
Age is: 29
Gender is: unknown
Gender is: unknown
```
```
...
@@ -238,7 +240,5 @@ Gender is: unknown
...
@@ -238,7 +240,5 @@ Gender is: unknown
![](
http://image.iswbm.com/20200607174235.png
)
![](
http://image.iswbm.com/20200607174235.png
)
source/c02/c02_10.rst
浏览文件 @
a194210c
2.10
反引号的妙用:结构体里的
Tag
用法
2.10
反引号的妙用:结构体里的
Tag
用法
======================================
======================================
|
image0
|
1.
抛砖引玉:什么是
Tag
?
-------------------------
正常情况下,你定义的结构体是这样子的,每个字段都由名字和字段类型组成
正常情况下,你定义的结构体是这样子的,每个字段都由名字和字段类型组成
..
code
::
go
..
code
::
go
...
@@ -85,14 +90,84 @@ Tag,也就是标签。
...
@@ -85,14 +90,84 @@ Tag,也就是标签。
{
"name"
:
"Jack"
,
"age"
:
22
}
{
"name"
:
"Jack"
,
"age"
:
22
}
{
"name"
:
"Jack"
,
"age"
:
22
,
"addr"
:
"China"
}
{
"name"
:
"Jack"
,
"age"
:
22
,
"addr"
:
"China"
}
那么问题就来了,通过
tag
,是如何做到这样的效果呢?
2.
不懂就问:如何定义获取
Tag
?
--------------------------------
Tag
由反引号包含,由一对或几对的键值对组成,通过空格来分割键值。格式如下
::
`
key01
:
"value01"
key02
:
"value02"
key03
:
"value03"
`
答案就是我们前几篇文章提到的
“
**
反射
**
”。
定义完后,如何从结构体中,取出
Tag
呢?
通过反射,可以从一个结构体对象中获得
tag
属性,然后进行解析,根据不同的
答案就是,我们上一节学过的
“反射”。
tag
属性来实现不同的逻辑。
这边我举个例子吧
获取
Tag
可以分为三个步骤:
1.
获取字段
field
2.
获取标签
tag
3.
获取键值对
key
:
value
演示如下
..
code
::
go
//
三种获取
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
的内容,会返回空字符串。
..
code
::
go
func
(
tag
StructTag
)
Get
(
key
string
)
string
{
v
,
_
:=
tag
.
Lookup
(
key
)
return
v
}
空
Tag
和不设置
Tag
效果是一样的
..
code
::
go
package
main
import
(
"fmt"
"reflect"
)
type
Person
struct
{
Name
string
``
Age
string
}
func
main
()
{
p
:=
reflect
.
TypeOf
(
Person
{})
name
,
_
:=
p
.
FieldByName
(
"Name"
)
fmt
.
Printf
(
"%q
\n
"
,
name
.
Tag
)
//
输出
""
age
,
_
:=
p
.
FieldByName
(
"Age"
)
fmt
.
Printf
(
"%q
\n
"
,
age
.
Tag
)
//
输出
""
}
3.
实战一下:利用
Tag
搞点事情?
--------------------------------
学会了如何定义
tag
和
获取
tag
,可以试着利用
tag
来做一些事情,来练习一下。
这边我举个例子吧。
如果我想实现一个函数(就叫
Print
吧),在打印
person
对象时,能够美化输出
..
code
::
go
..
code
::
go
...
@@ -107,15 +182,14 @@ tag 属性来实现不同的逻辑。
...
@@ -107,15 +182,14 @@ tag 属性来实现不同的逻辑。
Age
:
29
,
Age
:
29
,
}
}
Print
(
&
person
)
Print
(
person
)
如果我想实现一个函数(就叫
Print
吧),在打印
person
就像下面这样,
key
和
value
之间有个
``
is
:``\
,如果没有指定
Gender
对象时,能够美化输出,就像下面这样,
key
和
value
之间有个
的值,那么显示为
unknown
(未知)。
``
is
:``\
,如果没有指定
Gender
的值,那么显示为
unknown
(未知)。
..
code
::
shell
..
code
::
shell
Person
Name
:
MING
Name
is
:
MING
Age
is
:
29
Age
is
:
29
Gender
is
:
unknown
Gender
is
:
unknown
...
@@ -136,25 +210,16 @@ label 属性,而 Gender 多了一个 default 属性,意在指定默认值。
...
@@ -136,25 +210,16 @@ label 属性,而 Gender 多了一个 default 属性,意在指定默认值。
..
code
::
go
..
code
::
go
func
Print
(
ptr
interface
{})
error
{
func
Print
(
obj
interface
{})
error
{
//
取
Value
//
获取入参的类型
v
:=
reflect
.
ValueOf
(
obj
)
t
:=
reflect
.
TypeOf
(
ptr
)
//
入参类型校验
if
t
.
Kind
()
!= reflect.Ptr || t.Elem().Kind() != reflect.Struct {
return
fmt
.
Errorf
(
"参数应该为结构体指针"
)
}
//
取指针指向的结构体变量
v
:=
reflect
.
ValueOf
(
ptr
).
Elem
()
//
解析字段
//
解析字段
for
i
:=
0
;
i
<
v
.
NumField
();
i
++
{
for
i
:=
0
;
i
<
v
.
NumField
();
i
++
{
//
取
tag
//
取
tag
field
Info
:=
v
.
Type
().
Field
(
i
)
field
:=
v
.
Type
().
Field
(
i
)
tag
:=
field
Info
.
Tag
tag
:=
field
.
Tag
//
解析
label
和
default
//
解析
label
和
default
label
:=
tag
.
Get
(
"label"
)
label
:=
tag
.
Get
(
"label"
)
...
@@ -181,7 +246,10 @@ label 属性,而 Gender 多了一个 default 属性,意在指定默认值。
...
@@ -181,7 +246,10 @@ label 属性,而 Gender 多了一个 default 属性,意在指定默认值。
Age
is
:
29
Age
is
:
29
Gender
is
:
unknown
Gender
is
:
unknown
|
image0
|
到此,我们就把
Tag
的用法介绍完了。
|
image1
|
..
|
image0
|
image
::
http
://
image
.
iswbm
.
com
/
20200607174235.
png
..
|
image0
|
image
::
http
://
image
.
iswbm
.
com
/
20200607145423.
png
..
|
image1
|
image
::
http
://
image
.
iswbm
.
com
/
20200607174235.
png
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录