When a Go program needs to inspect an unknown value at runtime, reflect.Type describes its specific type. It is distinct from reflect.Value, which represents the value, and reflect.Kind, which identifies a broad category such as struct, pointer, or string. section 13.1
A useful case is checking an interface chosen at runtime. Obtain the concrete type with reflect.ValueOf(concrete).Type(). For a target supplied as a pointer to an interface, reflect.TypeOf(target).Elem() yields the interface type; then call the concrete type’s Implements method. The target must have that pointer-to-interface form, or this unchecked approach can panic. section 13.1.2
Listing 13.5 Determining whether a type implements an interface
package main
import (
"fmt"
"io"
"reflect"
)
type Name struct { #1
First, Last string
}
func (n *Name) String() string {
return n.First + " " + n.Last
}
func main() {
n := &Name{First: "Inigo", Last: "Montoya"}
stringer := (*fmt.Stringer)(nil) #2
implements(n, stringer) #3
writer := (*io.Writer)(nil) #4
implements(n, writer) #5
}
func implements(concrete interface{}, target interface{}) bool {
iface := reflect.TypeOf(target).Elem() #6
v := reflect.ValueOf(concrete) #7
t := v.Type() #7
if t.Implements(iface) { #8
fmt.Printf("%T is a %s\n", concrete, iface.Name())
return true
}
fmt.Printf("%T is not a %s\n", concrete, iface.Name())
return false
}
The listing tests a pointer to Name against fmt.Stringer and io.Writer using reflect.Type and Implements. section 13.1.2
reflect.Type also helps inspect structs. Start with a reflect.Value, obtain its Type, and examine fields while walking nested values. A recursive walker can report each field’s type and kind, following struct fields until it reaches nonstruct kinds. section 13.1.3
Value is type "main.Person" (struct)
Field "Name" is type "*main.Name" (struct)
Value is type "main.Name" (struct)
Field "Title" is type "string" (string)
Field "First" is type "string" (string)
Field "Last" is type "string" (string)
Field "Address" is type "*main.Address" (struct)
Value is type "main.Address" (struct)
Field "Street" is type "string" (string)
Field "Region" is type "string" (string)
The walker’s output makes the distinction between a pointer-typed field and the nested struct value visible. section 13.1.3
