BudiBadu Logo

Samplebadu

Code with Example
BudiBadu Logo
Samplebadu

Go by Example: Struct Tags

Go 1.23

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:"..."`.

Code Breakdown

12
Renaming a field. The struct field is 'Name', but the tag tells the JSON encoder to use "full_name" as the key in the JSON output.
13
Ignoring a field. The dash '-' is a special value that tells standard libraries to completely ignore this field. This is essential for security (e.g., never sending passwords in API responses).
14
The 'omitempty' option. Since 'Age' is 0 in our example (which is the zero value for int), the JSON encoder will simply leave this field out of the resulting JSON string.
43
Accessing tags with reflection. 'field.Tag.Get("json")' parses the tag string and returns the value associated with the "json" key. This is the mechanism libraries use to implement their logic.