What are the use(s) for struct tags in Go?

go, reflection, struct, tags

Solution

A tag for a field allows you to attach meta-information to the field which can be acquired using reflection. Usually it is used to provide transformation info on how a struct field is encoded to or decoded from another format (or stored/retrieved from a database), but you can use it to store whatever meta-info you want to, either intended for another package or for your own use.

As mentioned in the documentation of `reflect.StructTag`, by convention the value of a tag string is a space-separated list of `key:"value"` pairs, for example:

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.

If multiple information is to be passed in the `"value"`, usually it is specified by separating it with a comma (`','`), e.g.

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

Usually a dash value (`'-'`) for the `"value"` means to exclude the field from the process (e.g. in case of `json` it means not to marshal or unmarshal that field).

Example of accessing your custom tags using reflection

We can use reflection (`reflect` package) to access the tag values of struct fields. Basically we need to acquire the `Type` of our struct, and then we can query fields e.g. with `Type.Field(i int)` or `Type.FieldByName(name string)`. These methods return a value of `StructField` which describes / represents a struct field; and `StructField.Tag` is a value of type `StructTag` which describes / represents a tag value.

Previously we talked about "convention". This convention means that if you follow it, you may use the `StructTag.Get(key string)` method which parses the value of a tag and returns you the `"value"` of the `key` you specify. The convention is implemented / built into this `Get()` method. If you don't follow the convention, `Get()` will not be able to parse `key:"value"` pairs and find what you're looking for. That's also not a problem, but then you need to implement your own parsing logic.

Also there is `StructTag.Lookup()` (was added in Go 1.7) which is "like `Get()` but distinguishes the tag not containing the given key from the tag associating an empty string with the given key".

So let's see a simple example:

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

Output (try it on the 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 had a presentation about struct tags called:

The Many Faces of Struct Tags (slide) (and a video)

Here is a list of commonly used tag keys:

- `json ` - used by the `encoding/json` package, detailed at `json.Marshal()`

- `xml ` - used by the `encoding/xml` package, detailed at `xml.Marshal()`

- `bson ` - used by gobson, detailed at `bson.Marshal()`; also by the mongo-go driver, detailed at bson package doc

- `protobuf ` - used by `github.com/golang/protobuf/proto`, detailed in the package doc

- `yaml ` - used by the `gopkg.in/yaml.v2` package, detailed at `yaml.Marshal()`

- `db ` - used by the `github.com/jmoiron/sqlx` package; also used by `github.com/go-gorp/gorp` package

- `orm ` - used by the `github.com/astaxie/beego/orm` package, detailed at Models – Beego ORM

- `gorm ` - used by `gorm.io/gorm`, examples can be found in their docs

- `valid ` - used by the `github.com/asaskevich/govalidator` package, examples can be found in the project page

- `datastore` - used by `appengine/datastore` (Google App Engine platform, Datastore service), detailed at Properties

- `schema ` - used by `github.com/gorilla/schema` to fill a `struct` with HTML form values, detailed in the package doc

- `asn1 ` - used by the `encoding/asn1` package, detailed at `asn1.Marshal()` and `asn1.Unmarshal()`

- `csv ` - used by the `github.com/gocarina/gocsv` package

- `env ` - used by the `github.com/caarlos0/env` package

Problem

In the Go Language Specification, it mentions a brief overview of tags: 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" } ``` This is a very short explanation IMO, and I was wondering if anyone could provide me with what use these tags would be?

Original source

Related problems