A `reflect.Value` represents a Go value for runtime inspection. Start with `reflect.ValueOf(x)`, then use `Kind()` to identify its underlying kind or `Type()` to obtain its specific type. A named integer type, for example, has its own type while retaining an integer kind. section 13.1 section 13.1.1
Sum by kind rather than type
Suppose `sum` accepts values through `interface{}`. A type switch with an `int64` case does not match a separately named type based on `int64`. Instead, obtain `ref := reflect.ValueOf(val)` and switch on `ref.Kind()`. The example reads signed integers with `ref.Int()`, an unsigned integer with `ref.Uint()`, and a string with `ref.String()` before parsing it. Use a type switch instead when the specific type matters. section 13.1.1
Listing 13.3 A kind switch
package main
import (
"fmt"
"reflect"
"strconv"
)
type MyInt int64
func main() {
var a uint8 = 2
var b int = 37
var c string = "3.2"
var d MyInt = 1
res := sum(a, b, c, d)
fmt.Printf("Result: %f\n", res)
}
func sum(v ...interface{}) float64 {
var res float64 = 0
for _, val := range v {
ref := reflect.ValueOf(val) #1
switch ref.Kind() { #2
case reflect.Int, reflect.Int64: #3
res += float64(ref.Int()) #4
case reflect.Uint8:
res += float64(ref.Uint())
case reflect.String:
a, err := strconv.ParseFloat
(ref.String(), 64)
if err != nil {
panic(err)
}
res += a
default:
fmt.Printf("Unsupported type %T. Ignoring.\n", val)
}
}
return res
}
The Go listing shows `ValueOf`, `Kind`, `Int`, `Uint`, and `String` working together in the sum function. section 13.1.1
The same value inspection supports walking a struct at runtime. Begin with a value, use `reflect.Indirect(reflect.ValueOf(u))` to inspect through a pointer, and combine the resulting value with `reflect.Type` to report fields and recurse into nested structs. The walker prints a value’s type and kind alongside its field information. 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
}
}
}
The recursive walker places `reflect.Value` in a concrete struct-inspection program. section 13.1.3
