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












