golang 结构体标签_如何在Go中使用结构标签

news/2024/7/7 9:34:38

golang 结构体标签

介绍 (Introduction)

Structures, or structs, are used to collect multiple pieces of information together in one unit. These collections of information are used to describe higher-level concepts, such as an Address composed of a Street, City, State, and PostalCode. When you read this information from systems such as databases, or APIs, you can use struct tags to control how this information is assigned to the fields of a struct. Struct tags are small pieces of metadata attached to fields of a struct that provide instructions to other Go code that works with the struct.

结构或结构用于在一个单元中收集多条信息。 这些信息收集用于描述更高级别的概念,例如由StreetCityStatePostalCode组成的Address 。 从数据库或API等系统读取此信息时,可以使用struct标记来控制如何将此信息分配给struct的字段。 结构标签是附加到结构字段的一小段元数据,这些元数据为与该结构一起使用的其他Go代码提供了指令。

结构标签是什么样的? (What Does a Struct Tag Look Like?)

Go struct tags are annotations that appear after the type in a Go struct declaration. Each tag is composed of short strings associated with some corresponding value.

Go struct标签是在Go struct声明中的类型之后出现的注释。 每个标签由与一些相应值关联的短字符串组成。

A struct tag looks like this, with the tag offset with backtick ` characters:

struct标签看起来像这样,标签的偏移量是反引号`字符:

type User struct {
    Name string `example:"name"`
}

Other Go code is then capable of examining these structs and extracting the values assigned to specific keys it requests. Struct tags have no effect on the operation of your code without some other code that examines them.

然后其他Go代码能够检查这些结构并提取分配给它请求的特定键的值。 如果没有其他检查代码的结构标记,它们对代码的操作将没有任何影响。

Try this example to see what struct tags look like, and that without code from another package, they will have no effect.

尝试此示例以查看struct标记的外观,如果没有其他包中的代码,则它们将无效。

package main

import "fmt"

type User struct {
    Name string `example:"name"`
}

func (u *User) String() string {
    return fmt.Sprintf("Hi! My name is %s", u.Name)
}

func main() {
    u := &User{
        Name: "Sammy",
    }

    fmt.Println(u)
}

This will output:

这将输出:


   
Output
Hi! My name is Sammy

This example defines a User type with a Name field. The Name field has been given a struct tag of example:"name". We would refer to this specific tag in conversation as the “example struct tag” because it uses the word “example” as its key. The example struct tag has the value "name" for the Name field. On the User type, we also define the String() method required by the fmt.Stringer interface. This will be called automatically when we pass the type to fmt.Println and gives us a chance to produce a nicely formatted version of our struct.

本示例使用Name字段定义User类型。 “ Name字段已获得example:"name"的struct标签example:"name" 。 我们将会话中的这个特定标记称为“ example struct tag”,因为它使用单词“ example”作为其键。 该example结构的标签有值"name"Name字段。 在User类型上,我们还定义了fmt.Stringer接口所需的String()方法。 当我们将类型传递给fmt.Println时,它将被自动fmt.Println ,这使我们有机会生成结构良好的格式化版本。

Within the body of main, we create a new instance of our User type and pass it to fmt.Println. Even though the struct had a struct tag present, we see that it has no effect on the operation of this Go code. It will behave exactly the same if the struct tag were not present.

main ,我们创建一个User类型的新实例,并将其传递给fmt.Println 。 即使struct存在struct标记,我们仍然看到它对此Go代码的操作没有影响。 如果不存在struct标记,它将表现完全相同。

To use struct tags to accomplish something, other Go code must be written to examine structs at runtime. The standard library has packages that use struct tags as part of their operation. The most popular of these is the encoding/json package.

要使用struct标记完成某件事,必须编写其他Go代码以在运行时检查结构。 标准库包含使用struct标记作为其操作一部分的软件包。 其中最流行的是encoding/json包。

编码JSON (Encoding JSON)

JavaScript Object Notation (JSON) is a textual format for encoding collections of data organized under different string keys. It’s commonly used to communicate data between different programs as the format is simple enough that libraries exist to decode it in many different languages. The following is an example of JSON:

JavaScript Object Notation(JSON)是一种文本格式,用于对根据不同字符串键组织的数据集合进行编码。 它通常用于在不同程序之间进行数据通信,因为其格式非常简单,以至于存在库可以用许多不同的语言对其进行解码。 以下是JSON的示例:

{
  "language": "Go",
  "mascot": "Gopher"
}

This JSON object contains two keys, language and mascot. Following these keys are the associated values. Here the language key has a value of Go and mascot is assigned the value Gopher.

此JSON对象包含两个键, languagemascot 。 这些键之后是关联的值。 此处, language键的值为Gomascot的值为Gopher

The JSON encoder in the standard library makes use of struct tags as annotations indicating to the encoder how you would like to name your fields in the JSON output. These JSON encoding and decoding mechanisms can be found in the encoding/json package.

标准库中的JSON编码器使用struct标记作为注释,向编码器指示您希望如何在JSON输出中命名字段。 这些JSON编码和解码机制可以在encoding/json 包中找到 。

Try this example to see how JSON is encoded without struct tags:

请尝试以下示例,以了解如何在没有struct标签的情况下对JSON进行编码:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "os"
    "time"
)

type User struct {
    Name          string
    Password      string
    PreferredFish []string
    CreatedAt     time.Time
}

func main() {
    u := &User{
        Name:      "Sammy the Shark",
        Password:  "fisharegreat",
        CreatedAt: time.Now(),
    }

    out, err := json.MarshalIndent(u, "", "  ")
    if err != nil {
        log.Println(err)
        os.Exit(1)
    }

    fmt.Println(string(out))
}

This will print the following output:

这将打印以下输出:


   
Output
{ "Name": "Sammy the Shark", "Password": "fisharegreat", "CreatedAt": "2019-09-23T15:50:01.203059-04:00" }

We defined a struct describing a user with fields including their name, password, and the time the user was created. Within the main function, we create an instance of this user by supplying values for all fields except PreferredFish (Sammy likes all fish). We then passed the instance of User to the json.MarshalIndent function. This is used so we can more easily see the JSON output without using an external formatting tool. This call could be replaced with json.Marshal(u) to receive JSON without any additional whitespace. The two additional arguments to json.MarshalIndent control the prefix to the output (which we have omitted with the empty string), and the characters to use for indenting, which here are two space characters. Any errors produced from json.MarshalIndent are logged and the program terminates using os.Exit(1). Finally, we cast the []byte returned from json.MarshalIndent to a string and hand the resulting string to fmt.Println for printing on the terminal.

我们定义了一个结构,该结构使用字段(包括用户名,密码和创建用户的时间)来描述用户。 在main功能中,我们通过为除PreferredFish (Sammy喜欢所有鱼)之外的所有字段提供值来创建此用户的实例。 然后,我们将User的实例传递给json.MarshalIndent函数。 使用它是为了让我们可以更轻松地查看JSON输出,而无需使用外部格式化工具。 此调用可以替换为json.Marshal(u)来接收JSON,而无需任何其他空格。 json.MarshalIndent的两个附加参数控制输出的前缀(我们使用空字符串省略了该前缀)以及用于缩进的字符,这是两个空格字符。 记录json.MarshalIndent产生的任何错误,并使用os.Exit(1)终止程序。 最后,我们将从json.MarshalIndent返回的[]byte json.MarshalIndentstring ,并将所得的字符串传递给fmt.Println以在终端上进行打印。

The fields of the struct appear exactly as we named them. This is not the typical JSON style that you may expect, which uses camel casing for names of fields. You’ll change the names of the field to follow camel case style in this next example. As you’ll see when you run this example, this won’t work because the desired field names conflict with Go’s rules about exported field names.

结构的字段与我们命名的字段完全相同。 这不是您可能期望的典型JSON样式,它使用驼峰式大小写字段名称。 在下一个示例中,您将更改字段名称以遵循驼峰样式。 正如您在运行此示例时所看到的那样,该操作将无效,因为所需的字段名称与Go的有关导出的字段名称的规则相冲突。

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "os"
    "time"
)

type User struct {
    name          string
    password      string
    preferredFish []string
    createdAt     time.Time
}

func main() {
    u := &User{
        name:      "Sammy the Shark",
        password:  "fisharegreat",
        createdAt: time.Now(),
    }

    out, err := json.MarshalIndent(u, "", "  ")
    if err != nil {
        log.Println(err)
        os.Exit(1)
    }

    fmt.Println(string(out))
}

This will present the following output:

这将显示以下输出:


   
Output
{}

In this version, we’ve altered the names of the fields to be camel cased. Now Name is name, Password is password, and finally CreatedAt is createdAt. Within the body of main we’ve changed the instantiation of our struct to use these new names. We then pass the struct to the json.MarshalIndent function as before. The output, this time is an empty JSON object, {}.

在此版本中,我们更改了驼峰式的字段名称。 现在NamenamePasswordpassword ,最后CreatedAtcreatedAt 。 在main主体中,我们已更改结构的实例化以使用这些新名称。 然后,像以前一样,将结构传递给json.MarshalIndent函数。 这次的输出是一个空的JSON对象{}

Camel casing fields properly requires that the first character be lower-cased. While JSON doesn’t care how you name your fields, Go does, as it indicates the visibility of the field outside of the package. Since the encoding/json package is a separate package from the main package we’re using, we must uppercase the first character in order to make it visible to encoding/json. It would seem that we’re at an impasse, and we need some way to convey to the JSON encoder what we would like this field to be named.

骆驼的大小写正确要求第一个字符小写。 尽管JSON不在乎您如何命名字段,但Go会在乎,因为它表明了包外部字段的可见性。 由于encoding/json包是与我们正在使用的main包分开的包,因此我们必须将第一个字符大写以使其对encoding/json可见。 似乎我们陷入了僵局,我们需要某种方式将想要将此字段命名的内容传达给JSON编码器。

使用结构标签控制编码 (Using Struct Tags to Control Encoding)

You can modify the previous example to have exported fields that are properly encoded with camel-cased field names by annotating each field with a struct tag. The struct tag that encoding/json recognizes has a key of json and a value that controls the output. By placing the camel-cased version of the field names as the value to the json key, the encoder will use that name instead. This example fixes the previous two attempts:

您可以修改前面的示例,以通过使用struct标记对每个字段进行注释,使导出的字段使用驼峰式字段名正确编码。 结构体标记, encoding/json识别具有一个键json和一个值,控制输出。 通过将字段名称的驼峰式版本作为json键的值,编码器将改为使用该名称。 本示例解决了前两次尝试:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "os"
    "time"
)

type User struct {
    Name          string    `json:"name"`
    Password      string    `json:"password"`
    PreferredFish []string  `json:"preferredFish"`
    CreatedAt     time.Time `json:"createdAt"`
}

func main() {
    u := &User{
        Name:      "Sammy the Shark",
        Password:  "fisharegreat",
        CreatedAt: time.Now(),
    }

    out, err := json.MarshalIndent(u, "", "  ")
    if err != nil {
        log.Println(err)
        os.Exit(1)
    }

    fmt.Println(string(out))
}

This will output:

这将输出:


   
Output
{ "name": "Sammy the Shark", "password": "fisharegreat", "preferredFish": null, "createdAt": "2019-09-23T18:16:17.57739-04:00" }

We’ve changed the field names back to be visible to other packages by capitalizing the first letters of their names. However, this time we’ve added struct tags in the form of json:"name", where "name" was the name we wanted json.MarshalIndent to use when printing our struct as JSON.

我们通过将字段名称的首字母大写更改为其他软件包可以看到的字段名称。 但是,这次我们以json:"name"的形式添加了struct标记,其中"name"是我们想要的json.MarshalIndent在将struct打印为JSON时使用的名称。

We’ve now successfully formatted our JSON correctly. Notice, however, that the fields for some values were printed even though we did not set those values. The JSON encoder can eliminate these fields as well, if you like.

现在,我们已经成功地正确格式化了JSON。 但是请注意,即使我们没有设置这些值,某些值的字段也会被打印出来。 如果您愿意,JSON编码器也可以消除这些字段。

删除空的JSON字段 (Removing Empty JSON Fields)

Most commonly, we want to suppress outputting fields that are unset in JSON. Since all types in Go have a “zero value,” some default value that they are set to, the encoding/json package needs additional information to be able to tell that some field should be considered unset when it assumes this zero value. Within the value part of any json struct tag, you can suffix the desired name of your field with ,omitempty to tell the JSON encoder to suppress the output of this field when the field is set to the zero value. The following example fixes the previous examples to no longer output empty fields:

最常见的是,我们要禁止输出未在JSON中设置的字段。 由于Go中的所有类型都有一个“零值”(它们被设置为一些默认值),所以encoding/json包需要其他信息,以便能够在假定该字段为零时将某些字段视为未设置。 在任何json struct标记的value部分中,您可以在字段后缀所需的名称,omitempty告诉JSON编码器在该字段设置为零值时禁止显示该字段的输出。 下面的示例将前面的示例修复为不再输出空字段:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "os"
    "time"
)

type User struct {
    Name          string    `json:"name"`
    Password      string    `json:"password"`
    PreferredFish []string  `json:"preferredFish,omitempty"`
    CreatedAt     time.Time `json:"createdAt"`
}

func main() {
    u := &User{
        Name:      "Sammy the Shark",
        Password:  "fisharegreat",
        CreatedAt: time.Now(),
    }

    out, err := json.MarshalIndent(u, "", "  ")
    if err != nil {
        log.Println(err)
        os.Exit(1)
    }

    fmt.Println(string(out))
}

This example will output:

此示例将输出:


   
Output
{ "name": "Sammy the Shark", "password": "fisharegreat", "createdAt": "2019-09-23T18:21:53.863846-04:00" }

We’ve modified the previous examples so that the PreferredFish field now has the struct tag json:"preferredFish,omitempty". The presence of the ,omitempty augmentation causes the JSON encoder to skip that field, since we decided to leave it unset. This had the value null in our previous examples’ outputs.

我们已经修改了前面的示例,以便PreferredFish字段现在具有struct标签json:"preferredFish,omitempty" 。 由于我们决定不设置该字段,因此,omitempty扩充的存在会导致JSON编码器跳过该字段。 在我们先前示例的输出中,其值为null

This output is looking much better, but we’re still printing out the user’s password. The encoding/json package provides another way for us to ignore private fields entirely.

该输出看起来要好得多,但我们仍在打印用户密码。 encoding/json包为我们提供了另一种完全忽略私有字段的方法。

忽略私有字段 (Ignoring Private Fields)

Some fields must be exported from structs so that other packages can correctly interact with the type. However, the nature of these fields may be sensitive, so in these circumstances, we would like the JSON encoder to ignore the field entirely—even when it is set. This is done using the special value - as the value argument to a json: struct tag.

必须从结构导出某些字段,以便其他包可以与类型正确交互。 但是,这些字段的性质可能很敏感,因此在这种情况下,我们希望JSON编码器完全忽略该字段,即使设置了该字段也是如此。 这是通过使用特殊值-作为json: struct标记的value参数来完成的。

This example fixes the issue of exposing the user’s password.

本示例解决了公开用户密码的问题。

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "os"
    "time"
)

type User struct {
    Name      string    `json:"name"`
    Password  string    `json:"-"`
    CreatedAt time.Time `json:"createdAt"`
}

func main() {
    u := &User{
        Name:      "Sammy the Shark",
        Password:  "fisharegreat",
        CreatedAt: time.Now(),
    }

    out, err := json.MarshalIndent(u, "", "  ")
    if err != nil {
        log.Println(err)
        os.Exit(1)
    }

    fmt.Println(string(out))
}

When you run this example, you’ll see this output:

运行此示例时,将看到以下输出:


   
Output
{ "name": "Sammy the Shark", "createdAt": "2019-09-23T16:08:21.124481-04:00" }

The only thing we’ve changed in this example from previous ones is that the password field now uses the special "-" value for its json: struct tag. We see that in the output from this example that the password field is no longer present.

在本示例中,我们从以前的示例中唯一更改的是,密码字段现在为其json: struct标记使用特殊的"-"值。 我们在此示例的输出中看到, password字段不再存在。

These features of the encoding/json package, ,omitempty and "-", are not standards. What a package decides to do with values of a struct tag depends on its implementation. Because the encoding/json package is part of the standard library, other packages have also implemented these features in the same way as a matter of convention. However, it’s important to read the documentation for any third-party package that uses struct tags to learn what is supported and what is not.

encoding/json包的这些功能,omitempty"-"不是标准的。 包决定使用struct标记的值的方式取决于其实现。 因为encoding/json包是标准库的一部分,所以其他包也按照约定的相同方式实现了这些功能。 但是,阅读任何使用struct标记的第三方程序包的文档以了解支持的内容和不支持的内容非常重要。

结论 (Conclusion)

Struct tags offer a powerful means to augment the functionality of code that works with your structs. Many standard library and third-party packages offer ways to customize their operation through the use of struct tags. Using them effectively in your code provides both this customization behavior and succinctly documents how these fields are used to future developers.

结构标签提供了一种强大的手段来增强与您的结构一起使用的代码的功能。 许多标准库和第三方软件包都提供了使用struct标记自定义其操作的方法。 在您的代码中有效地使用它们提供了这种自定义行为,并简洁地记录了如何将这些字段用于将来的开发人员。

翻译自: https://www.digitalocean.com/community/tutorials/how-to-use-struct-tags-in-go

golang 结构体标签


http://www.niftyadmin.cn/n/3649550.html

相关文章

Windows 软件卸载清理工具 Geek Uninstaller

今天推荐一款好用的Windows系统下的软件卸载清理工具—:Geek Uninstaller 有时电脑遇到软件无法卸载, 软件残留注册表影响软件安装。 软件繁多,难于统一管理? Geek Uninstaller都可以解决。 软件免安装,单文件打开…

[EntLib]UAB(Updater Application Block)下载

下载地址:http://www.microsoft.com/downloads/details.aspx?FamilyIdC6C09314-E222-4AF2-9395-1E0BD7060786&displaylangenFile Name:ApplicationUpdater2.msiVersion: 2.0Date Published:4/8/2005UAB(Updater Application Block),你可以用它来从中…

【ARM Coresight 系列文章 3.1 - ARM Coresight DP 对 AP 的访问 1】

文章目录 1.1 DP 中相关寄存器的介绍1.1.1 DPACC and APACC 寄存器1.1.2 DP SELECT 寄存器1.1.3 AP CSW寄存器1.1.4 AP TAR 寄存器1.1.5 AP DRW寄存器1.1.6 AP Banked Data registers 1.1 DP 中相关寄存器的介绍 如果DAP接入的是JTAG接口,那么将会通过APACC寄存器来…

华为鸿蒙系统应用开发工具介绍 DevEco Studio

简单介绍华为鸿蒙系统应用开发工具 DevEco Studio的安装和使用 据说12月份鸿蒙系统会推出手机的SDK哦,作为一名普通的开发者,表示非常期待。 一、HUAWEI DevEco Studio 介绍 HUAWEI DevEco Studio 是华为消费者业务为开发者提供的集成开发环境&#xf…

go语言结构体数组定义_在Go中定义结构

go语言结构体数组定义介绍 (Introduction) Building abstractions around concrete details is the greatest tool that a programming language can give to a developer. Structs allow Go developers to describe the world in which a Go program operates. Instead of rea…

[Java] 利用xpdf库获取pdf文件的指定范围文本内容

[Java] 利用xpdf库获取pdf文件的指定范围文本内容编写者日期关键词郑昀ultrapower2005-8-2Java PDF xpdf读取PDF文件的某一部分文本内容,可以使用开源项目xpdf。从Java中调用xpdf,我们参照了《Java抽取Word,PDF的四种武器》文章最后提到的办法…

项目管理构建工具Maven的自定义安装

Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。 Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性,所以常常用两三行 M…

[Java] 利用Axis库调用C#的Web Service

[Java] 利用Axis库调用C#的Web Service编写者日期关键词郑昀ultrapower2005-8-2Java Web Service Axis C#试图从Java调用C#编写的Web Service,借用了王咏刚的wsCaller源代码中DynamicInvoker类。开始不清楚DynamicInvoker类的portName的含义,望文生义&am…