CodeNebula
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") // "", false

Full 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