Go by Example: Struct Tags
Struct tags allow you to attach metadata to struct fields. This is widely used by libraries like `encoding/json` to control serialization. This example shows how to define tags and access them using reflection.
Code
package main
import (
"encoding/json"
"fmt"
"reflect"
)
// 1. Defining Tags
// Tags are string literals inside backticks.
// Common keys: json, xml, yaml, validate, db.
type User struct {
Name string `json:"full_name"` // Rename field in JSON
Password string `json:"-"` // Ignore this field
Age int `json:"age,omitempty"` // Omit if zero value
Email string `json:"email" validate:"required,email"` // Multiple tags
}
func main() {
u := User{
Name: "John Doe",
Password: "secret_pass",
Age: 0, // Will be omitted due to omitempty
Email: "[email protected]",
}
// 2. Using Tags (JSON Marshaling)
// The json package reads the tags to decide how to format the output.
jsonData, _ := json.MarshalIndent(u, "", " ")
fmt.Println(string(jsonData))
// Output:
// {
// "full_name": "John Doe",
// "email": "[email protected]"
// }
// 3. Accessing Tags via Reflection
// This is how libraries like 'json' or 'validator' work under the hood.
t := reflect.TypeOf(u)
field, _ := t.FieldByName("Name")
fmt.Println("\nReflection Info:")
fmt.Println("Field:", field.Name)
fmt.Println("Tag (json):", field.Tag.Get("json"))
}
Explanation
Struct tags provide a powerful mechanism for attaching arbitrary metadata to struct fields, enabling declarative configuration that can be inspected and utilized by libraries at runtime through Go's reflection capabilities. These string literals, enclosed in backticks, effectively bridge the gap between Go's static type system and dynamic external formats, allowing for precise control over how data is serialized, deserialized, or validated without polluting the core logic of the application. Common use cases include defining JSON keys, database column mappings, and validation constraints.
The reflect package serves as the engine behind struct tags, allowing sophisticated libraries like encoding/json or ORMs to dynamically parse these annotations and modify their behavior accordingly. By leveraging this metadata-driven approach, developers can decouple their data structures from serialization concerns, ensuring that the internal representation of data remains clean and idiomatic while still satisfying the strict formatting requirements of external APIs, databases, and configuration files.
- Renaming:
`json:"my_name"`maps the struct field to "my_name". - Ignoring:
`json:"-"`tells the encoder to skip this field (great for passwords). - Omitting Empty:
`json:",omitempty"`skips the field if it has a zero value. - Multiple Tags: Separated by spaces:
`json:"..." xml:"..."`.

