What is the meaning of Tag in Go?

preface

Hello, everyone, I’m Asong. Today I want to share with you how structure tags are used in Go and how you can customize your own structure tag parsing.

When most beginners look at a company’s project code, they will see some structure definitions like this:

type Location struct {
	Longitude float32 `json:"lon,omitempty"`
	Latitude  float32 `json:"lat,omitempty"`
}
Copy the code

The field is followed by a label. What does this label do?

In the example above, the tag JSON :”lon, omitEmpty “means that when the structure field’s value is encoded as a JSON object, each exported field becomes a member of that object, named Lon or Lat, and when the field is empty, the exported field is not exported. Lon and lat are the names of the renamed members and omitEmpty is used to determine whether the members are exported or not.

Now, some of you might be wondering, how did you know how to use this? Can I label anything I want?

Let’s break it down a little bit. Drive!!

What is a label

The Go language provides structure tags that can be found by reflection. These are widely used in json/ XML, and the ORM framework also supports structure tags. The above example is used because Encoding/JSON supports structure tags, but it has its own tag rules; But they all have a general rule that cannot be changed in the following format:

`key1:"value1" key2:"value2" key3:"value3"... `  // Key-value pairs are separated by Spaces
Copy the code

Structure tags can have multiple key-value pairs, the key and value should be separated by colons, the value should be enclosed by double quotation marks, the key-value pairs should be separated by a space, never use commas!!

What if we want to pass multiple messages in a value? In encoding/ JSON, multiple values are separated by commas:

`json:"lon,omitempty"`
Copy the code

In GORM, multiple values are separated by semicolons:

`gorm:"column:id; primaryKey"Copy the code

You’ll have to look at your library’s documentation to see what kind of symbols you use.

Structure tags are associated with members at compile time, in the form of strings, which can be read by reflection at run time.

Now you know what is the structure tag, rule is the specification, but it’s easy to get wrong, because in the language compilation phase legal key/value pair will not do to the format of inspection, so we are not careful to write wrong, it is difficult to found, but we have the Go vet do inspection tools, specific to see an example of use:

type User struct {
	Name string `abc def ghk`
	Age uint16 ` ` 123-232
}
func main(a){}Copy the code

Then execute go vet main.go to obtain the execution result:

# command-line-arguments
go_vet_tag/main.go:4:2: struct field tag `abc def ghk` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair
go_vet_tag/main.go:5:2: struct field tag ` ` 123-232 not compatible with reflect.StructTag.Get: bad syntax for struct tag value
Copy the code

Bad syntax for struct tag pair tells us that key-value pair syntax is incorrect.

Therefore, it is necessary to introduce GO VET as a CI test in our program.

Label Usage Scenarios

Go officials have helped sort out which libraries already support struct tags: github.com/golang/go/w…

Tag Documentation
xml Godoc.org/encoding/xm…
json Godoc.org/encoding/js…
asn1 Godoc.org/encoding/as…
reform Godoc.org/gopkg.in/re…
dynamodb Docs.aws.amazon.com/sdk-for-go/…
bigquery Godoc.org/cloud.googl…
datastore Godoc.org/cloud.googl…
spanner Godoc.org/cloud.googl…
bson Godoc.org/labix.org/v….Godoc.org/go.mongodb….
gorm Godoc.org/github.com/…
yaml Godoc.org/gopkg.in/ya…
toml Godoc.org/github.com/…
validate Github.com/go-playgrou…
mapstructure Godoc.org/github.com/…
parser Godoc.org/github.com/…
protobuf Github.com/golang/prot…
db Github.com/jmoiron/sql…
url Github.com/google/go-q…
feature Github.com/nikolaydubi…

Json, YAML, GORm, validate, MapStructure, protobuf, etc. The structure tags are very common. Gin framework integrates validate library for parameter verification. This guy doesn’t know how to use the Validator library for validation yet.

Specific in these libraries is how to use, we can see the official documentation, write very detailed, specific scene specific use ha!!

Custom structure tags

Now we can answer the question at the beginning of the structure tag is free to write, as long as the rules of grammar, writing can be arbitrarily, but there is no support some libraries under the condition of the label, write the tag is doesn’t make any sense, if we want our label become meaningful, you need we provide analytical method. You can get tags by reflection, so let’s look at an example of how to get custom structure tags using reflection.

type User struct {
	Name string `asong:"Username"`
	Age  uint16 `asong:"age"`
	Password string `asong:"min=6,max=10"`
}
func getTag(u User) {
	t := reflect.TypeOf(u)

	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		tag := field.Tag.Get("asong")
		fmt.Println("get tag is ", tag)
	}
}

func main(a)  {
	u := User{
		Name: "asong",
		Age: 5,
		Password: "123456",
	}
	getTag(u)
}
Copy the code

The running results are as follows:

get tag is  Username
get tag is  age
get tag is  min=6,max=10
Copy the code

Here we use the TypeOf method to fetch the struct type, and then iterate over the fields. Each StructField has a member variable Tag:

// A StructField describes a single field in a struct.
type StructField struct {
	Name string
	PkgPath string
	Type      Type      // field type
	Tag       StructTag // field tag string
	Offset    uintptr   // offset within struct, in bytes
	Index     []int     // index sequence for Type.FieldByIndex
	Anonymous bool      // is an embedded field
}
Copy the code

Tag is a built-in type that provides both Get and Loopup methods to parse the value of the Tag and return the value of the specified key:

func (tag StructTag) Get(key string) string
func (tag StructTag) Lookup(key string) (value string, ok bool)
Copy the code

The inside of Get is also the Lookup method called. The difference is that a Lookup will tell you whether a given key is present in a tag by returning a value. Get ignores this judgment entirely.

conclusion

In this paper, we introduce the structure of the language label what is, and how to use reflection to obtain the solution structure tags, we in the daily development more is to use some libraries provide good label, rarely use their development, but we are interested can read validae source code, see how he tag in analytic structure. You can also implement a verification library as a hands-on project.

The code has been uploaded to github: github.com/asong2020/G…

Well, that’s the end of this article. I amasongAnd we’ll see you next time.

Welcome to the public account: Golang Dream Factory