在Go Language Specification中,它提到了标签的简要概述:
字段声明后面可以跟一个可选的字符串文字标记, 它成为相应的所有字段的属性 现场申报。标签通过反射可见 界面,但否则被忽略。
// 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" }
这是IMO的一个非常简短的解释,我想知道是否有人可以向我提供这些标签的用途?
答案 0 :(得分:516)
字段的标记允许您将元信息附加到可以使用反射获取的字段。通常它用于提供关于如何将结构字段编码到另一种格式或从另一种格式解码(或从数据库存储/检索)的转换信息,但是您可以使用它来存储您想要的任何元信息,或者用于另一个包装或供您自己使用。
正如reflect.StructTag
的文档中所提到的,按照惯例,标记字符串的值是以空格分隔的key:"value"
对列表,例如:
type User struct {
Name string `json:"name" xml:"name"`
}
key
通常表示后续"value"
所用的包,例如encoding/json
包处理/使用json
个键。
如果要在"value"
中传递多个信息,通常会通过用逗号(','
)分隔来指定,例如
Name string `json:"name,omitempty" xml:"name"`
通常'-'
的破折号值("value"
)表示从流程中排除字段(例如,在json
的情况下,它意味着不对该字段进行编组或解组)。
我们可以使用反射(reflect
包)来访问struct字段的标记值。基本上我们需要获取结构的Type
,然后我们可以查询字段,例如使用Type.Field(i int)
或Type.FieldByName(name string)
。这些方法返回值StructField
,它描述/表示结构域; StructField.Tag
是StructTag
类型的值,用于描述/表示标记值。
之前我们讨论过" convention" 。此约定意味着如果您遵循它,则可以使用StructTag.Get(key string)
方法来解析标记的值,并返回您指定的"value"
的{{1}}。 约定在此key
方法中实现/内置。如果您不遵守惯例,Get()
将无法解析Get()
对,并找到您正在寻找的内容。这也不是问题,但是你需要实现自己的解析逻辑。
此外还有StructTag.Lookup()
(已在Go 1.7中添加)"与key:"value"
类似,但将不包含给定键的标记与关联空字符串的标记区分开来给定的键" 。
所以让我们看一个简单的例子:
Get()
输出(在Go Playground上尝试):
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"))
}
GopherCon 2015有关于结构标记的演示文稿,名为:
The Many Faces of Struct Tags (slide) (以及video)
Field: User.Name
Whole tag value : "mytag:\"MyName\""
Value of 'mytag': "MyName"
Field: User.Email
Whole tag value : "mytag:\"MyEmail\""
Value of 'mytag': "MyEmail"
- 由encoding/json
包使用,详情请见json.Marshal()
json
- 由encoding/xml
包使用,详情请见xml.Marshal()
xml
- 由gobson使用,详情请见bson.Marshal()
bson
- 由github.com/golang/protobuf/proto
使用,详见包doc protobuf
- 由gopkg.in/yaml.v2
包使用,详情请见yaml.Marshal()
yaml
- 由github.com/jmoiron/sqlx
包使用;也被github.com/go-gorp/gorp
包db
- 由github.com/astaxie/beego/orm
包使用,详情请见Models – Beego ORM orm
- github.com/jinzhu/gorm
包使用的示例可以在他们的文档中找到:Models gorm
- 由github.com/asaskevich/govalidator
包使用,示例可在项目页面中找到valid
- 由appengine/datastore
(Google App Engine平台,数据存储区服务)使用,详情请见Properties datastore
- 由github.com/gorilla/schema
用来填充schema
的HTML表单值,详见包doc struct
- 由encoding/asn1
包使用,详情请见asn1.Marshal()
和asn1.Unmarshal()
asn
- 由github.com/gocarina/gocsv
包答案 1 :(得分:148)
以下是与encoding/json
包一起使用的标签的一个非常简单的示例,用于控制在编码和解码期间如何解释字段:
尝试直播:http://play.golang.org/p/BMeR8p1cKf
package main
import (
"fmt"
"encoding/json"
)
type Person struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
MiddleName string `json:"middle_name,omitempty"`
}
func main() {
json_string := `
{
"first_name": "John",
"last_name": "Smith"
}`
person := new(Person)
json.Unmarshal([]byte(json_string), person)
fmt.Println(person)
new_json, _ := json.Marshal(person)
fmt.Printf("%s\n", new_json)
}
// *Output*
// &{John Smith }
// {"first_name":"John","last_name":"Smith"}
json包可以查看该字段的标签,并告诉他们如何映射json< => struct字段,还有额外的选项,比如在序列化回json时是否应该忽略空字段。
基本上,任何包都可以使用字段上的反射来查看标记值并对这些值进行操作。在反射包中有更多关于它们的信息 http://golang.org/pkg/reflect/#StructTag:
按照惯例,标记字符串是可选的串联 空格分隔的键:“值”对。每个键都是非空字符串 由空间以外的非控制字符组成(U + 0020''), 引用(U + 0022'“')和冒号(U + 003A':')。使用引号引用每个值 U + 0022'“'字符和Go字符串文字语法。
答案 2 :(得分:2)
这是一种规范,用于指定程序包如何处理带有标记的字段。
例如:
type User struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
json标记通知json
数据包已整理以下用户的输出
u := User{
FirstName: "some first name",
LastName: "some last name",
}
会是这样的:
{"first_name":"some first name","last_name":"some last name"}
另一个例子是gorm
软件包标签声明了必须如何进行数据库迁移:
type User struct {
gorm.Model
Name string
Age sql.NullInt64
Birthday *time.Time
Email string `gorm:"type:varchar(100);unique_index"`
Role string `gorm:"size:255"` // set field size to 255
MemberNumber *string `gorm:"unique;not null"` // set member number to unique and not null
Num int `gorm:"AUTO_INCREMENT"` // set num to auto incrementable
Address string `gorm:"index:addr"` // create index with name `addr` for address
IgnoreMe int `gorm:"-"` // ignore this field
}
在此示例中,对于带有gorm标签的Email
字段,我们声明数据库中与该字段电子邮件对应的列必须为varchar类型且最大长度为100,并且还必须具有唯一索引。
另一个示例是binding
标记中非常常用的gin
标记。
type Login struct {
User string `form:"user" json:"user" xml:"user" binding:"required"`
Password string `form:"password" json:"password" xml:"password" binding:"required"`
}
var json Login
if err := c.ShouldBindJSON(&json); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
此示例中的绑定标签向gin包提供了提示,即发送到API的数据必须具有用户和密码字段,因为这些字段已按要求进行了标记。
因此,一般性标签是程序包需要了解的数据,它们应如何处理不同结构类型的数据,而全面了解程序包所需的标签的最佳方法是完整地阅读包装文档。 < / p>