liveBook · Manning

Reflection

As explained in Go in Practice, Second Edition

The Go reflect package provides runtime facilities for inspecting and manipulating the types and values of program data.

Reflection lets a Go program inspect values at runtime when their concrete types are not known in advance. The reflect package distinguishes a Value (the data), a Type (its specific Go type), and a Kind (its underlying category, such as struct, int, or slice). Start with reflect.ValueOf, then inspect the value’s Type and Kind. section 13.1

Choose the simplest test that solves the problem. A type switch handles known concrete types directly; a kind switch can group distinct types with the same underlying kind. For example, a type switch that handles int64 will not handle a separately defined int64-based type, while reflection can identify both as kind Int64. section 13.1.1

Sum values by kind

This runnable example accepts mixed values, including a defined integer type. ValueOf exposes each value’s kind; Int, Uint, and String retrieve data for conversion. package main import ( "fmt" "reflect" "strconv" ) type MyInt int64 func sum(values ...interface{}) float64 { var total float64 for _, value := range values { v := reflect.ValueOf(value) switch v.Kind() { case reflect.Int, reflect.Int64: total += float64(v.Int()) case reflect.Uint8: total += float64(v.Uint()) case reflect.String: n, err := strconv.ParseFloat(v.String(), 64) if err != nil { panic(err) } total += n } } return total } func main() { fmt.Println(sum(uint8(2), 37, "3.2", MyInt(1))) } section 13.1.1

Reflection also answers questions about interfaces and structs. To test an interface chosen at runtime, obtain its reflect.Type and call Implements on the concrete type; for a fixed interface, a type assertion is simpler. To inspect a struct, use reflect.Indirect to follow a pointer, then walk its fields and recurse into nested structs. section 13.1.2 section 13.1.3

Struct tags turn that inspection into configurable behavior. An `ini:"total"` tag can supply an output field name; a Marshaler reads field tags and values, while an Unmarshaler matches names and converts input before setting fields. The name–value encoder example supports selected field kinds rather than every possible Go value. 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
}

The Marshal listing shows the field loop, tag lookup, struct-kind check, and extraction of each field’s value. section 13.2.3

Reflection is useful for variable-format data and custom encoders, but it adds runtime cost and code complexity. Prefer ordinary type checks when they suffice; consider code generation when extensive runtime reflection would make an implementation cumbersome. section 3.1.4 section 13.0

How Go in Practice, Second Edition covers it

How deep it goes
Works through values, types, kinds, interface checks, recursive field inspection, and a limited custom encoder and decoder.
Examples
Uses a mixed-type sum, an interface-implementation check, a recursive struct walker, and tagged name–value encoding.
What it assumes
Assumes familiarity with Go values, structs, and interfaces while defining reflection’s values, types, and kinds.
What you can do after
Build it from scratch: inspect Go values and implement a limited tag-driven Marshal and Unmarshal pair.
How it connects
Connects reflection to type switches, interfaces, struct tags, marshaling, and code generation.

Also explained in

Compare how 13 books explain reflection →

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.