liveBook · Manning

Reflect.Kind

As explained in Go in Practice, Second Edition

reflect.Kind is a Go reflection enumeration identifying the broad underlying category of a value's type.

When a function accepts arbitrary Go values, a type switch can select behavior for each concrete type. That becomes repetitive when several types need the same treatment. A defined type such as `type MyInt int64` also needs its own type-switch case. `reflect.Kind` identifies a value’s broader category instead: `MyInt` has its own type but the kind `reflect.Int64`. Go’s `reflect` package also distinguishes the value, represented by `reflect.Value`, from its type, available through `reflect.Type`. section 13.1 section 13.1.1

Sum values by kind

This program accepts mixed values, converts the supported kinds to `float64`, and prints `43.200000`: ```go package main import ( "fmt" "reflect" "strconv" ) type MyInt int64 func sum(values ...interface{}) float64 { var total float64 for _, value := range values { reflected := reflect.ValueOf(value) switch reflected.Kind() { case reflect.Int, reflect.Int64: total += float64(reflected.Int()) case reflect.Uint8: total += float64(reflected.Uint()) case reflect.String: number, err := strconv.ParseFloat(reflected.String(), 64) if err != nil { panic(err) } total += number default: fmt.Printf("Unsupported type %T. Ignoring.\n", value) } } return total } func main() { fmt.Printf("Result: %f\n", sum(uint8(2), 37, "3.2", MyInt(1))) } ``` `reflect.ValueOf` obtains a reflection value; `Kind()` supplies the switch condition. The `reflect.Int64` case accepts `MyInt` without naming that type. Choose a type switch when behavior depends on specific types; a kind switch is less common, but useful when the same operation applies across underlying categories. section 13.1.1

Kinds also guide runtime inspection. A struct walker can inspect a value’s type and kind, then recurse through struct fields until it reaches nonstruct kinds. Pointer values need attention during that walk; `reflect.Indirect(reflect.ValueOf(u))` obtains the value being examined. 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
            }
     }
}

See the recursive value walker for a larger example combining types, values, kinds, and pointer indirection. section 13.1.3

How Go in Practice, Second Edition covers it

How deep it goes
Defines kinds alongside values and types, then works through a kind switch and recursive struct inspection.
Examples
Uses a mixed-value sum with a defined integer type and a recursive walker over integers and structs.
What it assumes
Assumes Go interfaces and switches while defining the reflection distinctions among values, types, and kinds.
What you can do after
Build it from scratch: dispatch on reflected kinds and inspect struct values recursively at runtime.
How it connects
Connects reflect.Value, reflect.Type, type switches, defined types, and struct field inspection.

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.