Golang的反射由reflect包提供支持,有两个重要类型:一个Type表示一个Go类型,它是一个接口。一个Value可以持有任意类型的值。
import (
"fmt"
"reflect"
"strconv"
)
func Display(name string, x interface{}) {
fmt.Printf("Display %s (%T):\n", name, x)
display(name, reflect.ValueOf(x))
}
func formatAtom(v reflect.Value) string {
switch v.Kind() {
case reflect.Invalid:
return "invalid"
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
reflect.Int64:
return strconv.FormatInt(v.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
reflect.Uint64:
return strconv.FormatUint(v.Uint(), 10)
case reflect.Bool:
return strconv.FormatBool(v.Bool())
case reflect.String:
return strconv.Quote(v.String())
case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Slice, reflect.Map:
return v.Type().String() + "0x" + strconv.FormatUint(uint64(v.Pointer()), 16)
default:
return v.Type().String() + "value"
}
}
func display(path string, v reflect.Value) {
switch v.Kind() {
case reflect.Invalid:
fmt.Printf("%s = invalid\n", path)
case reflect.Slice, reflect.Array:
for i := 0; i < v.Len(); i++ {
display(fmt.Sprintf("%s[%d]", path, i), v.Index(i))
}
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
fieldPath := fmt.Sprintf("%s.%s", path, v.Type().Field(i).Name)
display(fieldPath, v.Field(i))
}
case reflect.Map:
for _, key := range v.MapKeys(){
display(fmt.Sprintf("%s[%s]", path, formatAtom(key)), v.MapIndex(key))
}
case reflect.Ptr:
if v.IsNil() {
fmt.Printf("%s = nil\n", path)
} else {
display(fmt.Sprintf("*%s", path), v.Elem())
}
case reflect.Interface:
if v.IsNil() {
fmt.Printf("%s = nil\n", path)
} else {
fmt.Printf("%s.type = %s\n", path, v.Elem().Type())
display(path+".value", v.Elem())
}
default:
fmt.Printf("%s = %s\n", path, formatAtom(v))
}
}
import "testing"
type Movie struct {
Title, Subtitle string
Year int
Color bool
Actor map[string]string
Oscars []string
Sequel *string
}
var strangelove = Movie{
Title: "Dr. Strangelove",
Subtitle: "How I Learned to Stop Worrying and Love the Bomb",
Year: 1964,
Color: false,
Actor: map[string]string{
"Dr. Strangelove": "Peter Sellers",
"Grp. Cat. Lionel Mandrake": "Peter Sellers",
"Gen. Buck Turgidson": "George Hayden",
},
Oscars: []string{
"Best Actor (Nomin.)",
"Best Adapted Screeenplay (Nomin.)",
},
}
func TestDisplay(t *testing.T) {
Display("strangelove",strangelove)
}
Display strangelove (main.Movie):
strangelove.Title = “Dr. Strangelove”
strangelove.Subtitle = “How I Learned to Stop Worrying and Love the Bomb”
strangelove.Year = 1964
strangelove.Color = false
strangelove.Actor[“Dr. Strangelove”] = “Peter Sellers”
strangelove.Actor[“Grp. Cat. Lionel Mandrake”] = “Peter Sellers”
strangelove.Actor[“Gen. Buck Turgidson”] = “George Hayden”
strangelove.Oscars[0] = “Best Actor (Nomin.)”
strangelove.Oscars[1] = “Best Adapted Screeenplay (Nomin.)”
strangelove.Sequel = nil