liveBook · Manning

Type.NumField

As explained in Go in Practice, Second Edition

Type.NumField is a Go reflect method that returns the number of fields declared in a struct type.

Type.NumField returns the number of fields declared by a struct type. Combined with Type.Field, it supports indexed traversal of a struct’s metadata; the matching index on reflect.Value accesses the corresponding field value. section 13.1.3

A reflection-based struct walker uses Type.NumField in a small sequence:

  • Obtain a reflect.Value with reflect.ValueOf and remove a possible pointer with reflect.Indirect. section 13.1.3
  • Inspect the value’s type and confirm that its kind is reflect.Struct before enumerating fields. section 13.1.3
  • Loop from zero to Type.NumField, then use Type.Field with each index to inspect the field name and data type. section 13.1.3
  • Use the same index with Value.Field to obtain the field value, following pointer fields with reflect.Indirect when needed. section 13.1.3
Listing 13.7 Recursively examining a value
func main() {
     fmt.Println("Walking a simple integer")
     var one MyInt = 1   #1
     walk(one, 0)        #1
     fmt.Println("Walking a simple struct")
     two := struct{ Name string }{"foo"}    #2
     walk(two, 0)                           #2
fmt.Println("Walking a struct with struct fields") #2
     p := &Person{                                       #3
            Name:    &Name{"Count", "Tyrone", "Rugen"
            },                                          
            Address: &Address{"Humperdink Castle", 
            "Florian"},                                   
     }                                                  
     walk(p, 0)                                         
}
type MyInt int
type Person struct {
     Name    *Name
     Address *Address
}
type Name struct {
     Title, First, Last string
}
type Address struct {
     Street, Region string
}
func walk(u interface{}, depth int) {            #4
     val := reflect.Indirect(reflect.ValueOf(u))   #5
     t := val.Type()   #6
     tabs := strings.Repeat("\t", depth+1)   #7
     fmt.Printf("%sValue is type %q (%s)\n", tabs, t, val.Kind())
     if val.Kind() == reflect.Struct {   #8
            for i := 0; i < t.NumField(); i++ {
                   field := t.Field(i)                  #9
                   fieldVal := reflect.Indirect
                   (val.Field(i))                            
                   tabs := strings.Repeat("\t", depth+2)
                   fmt.Printf("%sField %q is type %q (%s)\n",
                          tabs, field.Name, field.Type, fieldVal.Kind())
                   if fieldVal.Kind() == 
                   reflect.Struct {                             #10
                          walk(fieldVal.Interface(), depth+1)   #10
                   }                                            #10
            }
     }
}

A recursive walker applies Type.NumField and Type.Field to simple structs and nested pointer-to-struct fields. section 13.1.3

How Go in Practice, Second Edition covers it

How deep it goes
Explains field counting and indexed traversal, then stops short of broader reflection behavior.
Examples
Uses a recursive walker over anonymous structs, Person, Name, and Address values, including pointer fields.
What it assumes
Assumes basic Go structs and pointers, while introducing reflect.Value, reflect.Type, and reflect.StructField relationships.
What you can do after
Build a recursive struct walker that reports field names, types, and corresponding values.
How it connects
Connects reflection to reflect.Type, reflect.StructField, reflect.Value, Type.Field, Value.Field, and reflect.Indirect.

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.