https://stackoverflow.com/questions/10858787/what-are-the-uses-for-struct-tags-in-go
问题
在 Go 语言规范 中,简述了标签:
A field declaration may be followed by an optional string literal tag, which becomes an attribute for all the fields in the corresponding field declaration. The tags are made visible through a reflection interface but are otherwise ignored.
译:字段的声明后可以添加可选的描述字符串标签,它成为相应字段声明中的属性。标签通过反射接口可见,否则会被忽略。
// A struct corresponding to the TimeStamp protocol buffer. // The tag strings define the protocol buffer field numbers. struct { microsec uint64 "field 1" serverIP6 uint64 "field 2" process string "field 3" }
这是一个非常简短的描述,而我想知道这些标签可以用来做什么?
回答
字段的标记允许您将元信息附加到可以使用反射获取的字段。通常它用于提供有关如何将结构字段编码为另一种格式或从另一种格式解码(或从数据库中存储/检索)的转换信息,但您可以使用它来存储您想要的任何元信息,用于另一个包,或自己使用。
根据文档 reflect.StructTag,按照约定,标签字符串是一个用空格分隔开的 key:"value"
键值对组成的列表,比如:
type User struct {
Name string `json:"name" xml:"name"`
}
key
通常表示对应 "value"
所针对的包,例如 json
键被 encoding/json
包所处理或使用。
如果 "value"
中需要传递多个信息,通常用逗号(','
)隔开,比如:
Name string `json:"name,omitempty" xml:"name"`
一般来说,"value"
中的横线('-'
)表示这个字段需要在处理中被跳过(比如在 json
中表示这个不要序列化或反序列化这个字段)。
用反射访问自定义标签的例子
可以使用反射(reflect 包)来访问结构体字段的标签。首先需要获取结构体的 Type,然后就可以访问字段,例如用 Type.Field(i int)
或 Type.FieldByName(name string)
。这些方法返回一个描述结构体字段的 StructField
值;而 StructField.Tag
是一个 StructTag
值,它描述该字段的标签。
之前我们谈到过“约定”。这个约定意味着如果你遵守它,就可以用 StructTag.Get(key string)
函数解析标签的值并返回你指定的 key
所对应的 "value"
。这个“约定”在函数 Get()
中被实现。如果你不遵守约定也没问题,只是 Get()
无法正确解析 key:"value"
并找到你需要的键值对,你需要自己实现自定义解析逻辑。
同时也有一个和 Get()
很相似的 StructTag.Lookup()
函数(在 Go 1.7 中被添加),它添加一个布尔返回值来区分键是否存在。
来看一些简单的例子:
type User struct {
Name string `mytag:"MyName"`
Email string `mytag:"MyEmail"`
}
u := User{"Bob", "bob@mycompany.com"}
t := reflect.TypeOf(u)
for _, fieldName := range []string{"Name", "Email"} {
field, found := t.FieldByName(fieldName)
if !found {
continue
}
fmt.Printf("\nField: User.%s\n", fieldName)
fmt.Printf("\tWhole tag value : %q\n", field.Tag)
fmt.Printf("\tValue of 'mytag': %q\n", field.Tag.Get("mytag"))
}
输出(在 Go Playground 中尝试):
Field: User.Name
Whole tag value : "mytag:\"MyName\""
Value of 'mytag': "MyName"
Field: User.Email
Whole tag value : "mytag:\"MyEmail\""
Value of 'mytag': "MyEmail"
GopherCon 2015 介绍了结构体标签:
The Many Faces of Struct Tags (slide) (以及对应的 视频)。
一些使用标签的例子
json
– 在encoding/json
库中,详见json.Marshal()
xml
– 在encoding/xml
库中,详见xml.Marshal()
bson
– 在 gobson 库中,详见bson.Marshal()
; 也在 mongo-go 驱动中,详见 bson package docprotobuf
– 在github.com/golang/protobuf/proto
库中,详见文档yaml
– 在gopkg.in/yaml.v2
库中,详见yaml.Marshal()
db
– 在github.com/jmoiron/sqlx
和github.com/go-gorp/gorp
库中orm
– 在github.com/astaxie/beego/orm
库中,详见 Models – Beego ORMgorm
– 在gorm.io/gorm
库中,具体见 docsvalid
– 在github.com/asaskevich/govalidator
库中,具体可以见项目示例datastore
– 在appengine/datastore
(Google App Engine platform, Datastore service) 库中,详见 Propertiesschema
– 在github.com/gorilla/schema
库中,用于从HTML 表格数据填充struct
,具体见项目文档asn
– 在encoding/asn1
库中,详见asn1.Marshal()
andasn1.Unmarshal()
csv
– 在github.com/gocarina/gocsv
库中env
– 在github.com/caarlos0/env
库中