Go 中如何使用结构体标签

译者:baiyutang

原文:https://www.digitalocean.com/community/tutorials/how-to-use-struct-tags-in-go

介绍

结构体,被用于搜集多个信息片段到一起集合到一个单元。这些信息集合被用于描述较高层级概念,如 Address,由 StreetCityStatePostalCode 组成。当你从数据库、API 等系统中读取信息时,你可以使用结构体标签控制信息如何给一个结构体的字段赋值。结构体标签是附着在一个结构体字段上的小块元数据,给使用结构体的 Go 代码提供指令。

结构体标签看起来是什么

结构体标签是出现在 Go 结构体类型声明后面的注释,每个标签由短字符关联相应的值组成。

一个结构体标签看起来如下,标签偏移带有反引号 ` 符号。

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

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

试试这个例子,看看结构体标签是什么样子的,如果没有来自另一个包的代码,它们将没有效果。

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)
}

它会输出

Output
Hi! My name is Sammy

JSON 编码

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

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

 试试这个例子,看看 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))
}

这会打印如下输出

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

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))
}

使用结构体标签控制编码

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))
}

这会输出

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

移出结构体空字段

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))
}

这个例子将输出

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

忽略私有字段

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))
}

当你运营这个例子,你将看到这个输出:

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

总结

结构体标签提供一种强大的方法,增大结构体作用的代码功能。很多标准库和第三方库通过结构体标签来提供方式定制操作。在代码中有效地使用它们不仅提供了这种定制行为,还简洁地记录了将来的开发人员如何使用这些字段。

本文文字及图片出自 InfoQ

余下全文(1/3)
分享这篇文章:

请关注我们:

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注