liveBook · Manning

Struct tag

As explained in Go in Practice, Second Edition

A struct tag is a Go field annotation containing metadata, commonly expressed as whitespace-separated key-value pairs for controlling data encoding or other processing.

A struct tag attaches metadata to a Go struct field. It is a backtick-quoted string after the field’s type. The string is freeform, but the usual convention is whitespace-separated entries such as `json:"animal_name"` and `xml:"AnimalName"`. A tag does nothing by itself: code that reads the struct decides which entries to use. section 3.1.4 section 13.2.1

Listing 3.4 Formatting data as JSON
package main

import (
    "fmt"
    "encoding/json"
)

type Animal struct {                       #1
    Name string `json:"animal_name"`                   #2
    ScientificName string `json:"scientific_name"`     #2
    Weight float32 `json:"animal_average_weight"`      #2
}

func main() {
    a := Animal{
        Name: "cat",
        ScientificName: "Felis catus",
        Weight: 10.5,
    }                     #3

    output, err := json.Marshal(a)
    if err != nil {
        panic("couldn't encode json")
    }
    fmt.Println(string(output))     #4
}

The exported Go fields have `json` tags naming the output fields. `json.Marshal` uses those names; without the tags, it would use the Go field names. section 3.1.5

The field names are capitalized so `encoding/json` can access them. The tags let the JSON names follow a different convention without changing the Go names. A struct can also carry tags for more than one processor: a JSON encoder selects its `json` entry and ignores an `xml` entry. A JSON tag can include options after the name, as in `json:"lastName,omitempty"`. section 3.1.5 section 13.2.1

Tags are not limited to encoding. A `help` tag can supply an error message, and a `validate` tag can hold a regular expression for application-written checks. Neither behavior happens automatically: the relevant code must retrieve and interpret the value. Reflection provides access to a field’s tags at runtime, although its runtime cost and added complexity make it a tool to use deliberately. section 3.1.4 section 13.2.2

Listing 13.11 The Processes struct with annotations
type Processes struct {
     Total    int     `ini:"total"`
     Running  int     `ini:"running"`
     Sleeping int     `ini:"sleeping"`
     Threads  int     `ini:"threads"`
     Load     float32 `ini:"load"`
}

A custom `ini` tag maps each struct field to a key in a simple name-value file. Defining that mapping is only the first step; Go does not automatically parse the file from these annotations. section 13.2.3

Listing 13.14 The Marshal function
func fieldName(field reflect.StructField) string {    #1
     if t := field.Tag.Get("ini"); t != "" {        #2
            return t                                #2
     }
     return field.Name   #3
}

func Marshal(v interface{}) ([]byte, error) {
     var b bytes.Buffer
     val := reflect.Indirect(reflect.ValueOf(v))   #4
     if val.Kind() != reflect.Struct {   #5
            return []byte{}, errors.New("unmarshal can only take structs")
     }
     t := val.Type()
     for i := 0; i < t.NumField(); i++ {   #6
            f := t.Field(i)
            name := fieldName(f)   #7
            raw := val.Field(i).Interface()
            fmt.Fprintf(&b, "%s=%v\n", name, raw)    #8
     }
     return b.Bytes(), nil   #9
}

This encoder uses reflection to visit fields. Its `fieldName` helper reads `field.Tag.Get("ini")`, falling back to the Go field name when the tag is empty, before writing each `name=value` line. section 13.2.3

A matching decoder scans input lines, matches their keys against the same field-name rule, and converts values before setting fields. This is the practical boundary of a custom tag: choose a format, then implement the behavior that gives it meaning. section 13.2.3

How Go in Practice, Second Edition covers it

How deep it goes
Moves from tag syntax and JSON output to runtime tag lookup and a reflection-based encoder and decoder.
Examples
Uses JSON-encoded animal data, help and validation tags, and an INI-style process-data encoder and decoder.
What it assumes
Assumes familiarity with Go structs and fields; introduces tag syntax before developing reflection-based processing.
What you can do after
Build it from scratch: define a custom field-tag convention and read it with `reflect` in marshaling and unmarshaling code.
How it connects
Connects struct fields and visibility to JSON and XML encoding, reflection, and data validation.

Also explained in

Compare how 3 books explain struct tag →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go in Practice, Second Edition. The section links point to the parts of the book it draws on.