Go🚀Advancedadvanced
Struct Tags in Depth
Go · Advanced · Run with go run
Explanation
A struct tag is a raw string literal after a field, holding metadata read at runtime via reflection. By convention it's a space-separated list of `key:"value"` pairs — `json`, `xml`, `db`, `validate`, and others each claim a key. Libraries call `reflect.StructField.Tag.Get("key")` to read their slice. Tags are the backbone of Go's declarative serialization and validation.
Real-World Scenario
One `User` struct is persisted to a SQL database, serialized to a JSON API response, and validated on input. Three tag keys on each field — `db:"user_name"`, `json:"name"`, `validate:"required,min=2"` — let three independent libraries each map the field correctly, without three separate struct definitions.
Quick Snippet
snippet.go
type User struct {
ID int `json:"id" db:"user_id"`
Name string `json:"name" db:"user_name" validate:"required,min=2"`
Email string `json:"email,omitempty" db:"email" validate:"email"`
pass string `json:"-"` // unexported + ignored by json
}
// Reading tags via reflection
t := reflect.TypeOf(User{})
field, _ := t.FieldByName("Name")
field.Tag.Get("json") // "name"
field.Tag.Get("db") // "user_name"
field.Tag.Get("validate") // "required,min=2"
// Lookup distinguishes "absent" from "empty"
value, ok := field.Tag.Lookup("xml") // "", falseFull Example
struct_tags.go
// Compile: go run struct_tags.go
// Output:
// Name json tag: name
// Name db tag: user_name
// Name validate tag: required,min=2
// xml tag present: false
// JSON: {"id":1,"name":"Alice"}
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type User struct {
ID int `json:"id" db:"user_id"`
Name string `json:"name" db:"user_name" validate:"required,min=2"`
Email string `json:"email,omitempty" db:"email" validate:"email"`
}
func main() {
t := reflect.TypeOf(User{})
name, _ := t.FieldByName("Name")
fmt.Println("Name json tag:", name.Tag.Get("json"))
fmt.Println("Name db tag:", name.Tag.Get("db"))
fmt.Println("Name validate tag:", name.Tag.Get("validate"))
// Lookup distinguishes "absent" from "empty"
_, ok := name.Tag.Lookup("xml")
fmt.Println("xml tag present:", ok)
// Tags drive json serialization — Email is empty so omitempty drops it
data, _ := json.Marshal(User{ID: 1, Name: "Alice"})
fmt.Println("JSON:", string(data))
}
Run command
go run struct_tags.go