Go 中 struct 标签的用途是什么?

新手上路,请多包涵

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 的一个非常简短的解释,我想知道是否有人可以向我提供这些标签的用途?

原文由 liamzebedee 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 523
2 个回答

字段的标记允许您将元信息附加到可以使用反射获取的字段。通常它用于提供有关如何将结构字段编码为另一种格式或从另一种格式解码(或从数据库中存储/检索)的转换信息,但您可以使用它来存储您想要的任何元信息,或者用于另一个包装或供您自己使用。

正如 reflect.StructTag 的文档中所述,按照惯例,标记字符串的值是 key:"value" 对的空格分隔列表,例如:

 type User struct {
    Name string `json:"name" xml:"name"`
}

The key usually denotes the package that the subsequent "value" is for, for example json keys are processed/used by the encoding/json package.

如果要在 "value" 中传递多个信息,通常用逗号分隔指定( ',' ),例如

Name string `json:"name,omitempty" xml:"name"`

通常, --- 的短划线值 ( '-' "value" 意味着从流程中排除该字段(例如,在 json 的情况下,它意味着 unmar 或 notbe mar–场地)。

使用反射访问自定义标签的示例

我们可以使用反射( reflect 包)来访问结构字段的标签值。基本上我们需要获取我们结构的 Type ,然后我们可以查询字段,例如 Type.Field(i int)Type.FieldByName(name string) 。这些方法返回一个值 StructField 描述/代表一个结构字段;和 StructField.Tag 是类型 [ StructTag ] 6 的值,它描述/表示标签值。

之前我们谈到了 “约定” 。这个约定意味着如果你遵循它,你可以使用 StructTag.Get(key string) 方法解析标签的值并返回你指定的 "value"key .该 约定 已实现/内置到此 Get() 方法中。如果您不遵循约定, Get() 将无法解析 key:"value" 对并找到您要查找的内容。这也不是问题,但是您需要实现自己的解析逻辑。

还有 StructTag.Lookup() (在 Go 1.7 中添加) “类似于 Get() 但将不包含给定键的标签与将空字符串与给定键相关联的标签区分开来”

那么让我们看一个简单的例子:

 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 有一个关于结构标签的演示文稿,名为:

结构标签的多面性(幻灯片) (和 视频

以下是常用标签键的列表:

原文由 icza 发布,翻译遵循 CC BY-SA 4.0 许可协议

这是一个非常简单的标签示例,它与 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 时是否应该忽略空字段。

基本上,任何包都可以在字段上使用反射来查看标签值并根据这些值采取行动。在 reflect 包中有更多关于它们的信息

http://golang.org/pkg/reflect/#StructTag

按照惯例,标记字符串是可选的空格分隔键:“值”对的串联。每个键都是一个非空字符串,由除空格(U+0020 ‘ ‘)、引号(U+0022 ‘“‘)和冒号(U+003A ‘:‘)之外的非控制字符组成。每个值都被引用使用 U+0022 ‘”’ 字符和 Go 字符串文字语法。

原文由 jdi 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题