《GO程序设计语言》设计中案例,仅作为笔记进行收藏。反射案例。
package display
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, reflect.Uintptr:
return strconv.FormatUint(v.Uint(), 10)
case reflect.Bool:
if v.Bool() {
return "true"
}
return "false"
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: // reflect.Array, reflect.Struct, reflect.Interface
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: // basic types, channels, funcs
fmt.Printf("%s = %s\n", path, formatAtom(v))
}
}
package display
import (
"io"
"net"
"os"
"reflect"
"sync"
"testing"
)
func Example_slice() {
Display("slice", []*int{new(int), nil})
// Output:
// Display slice ([]*int):
// (*slice[0]) = 0
// slice[1] = nil
}
func Example_nilInterface() {
var w io.Writer
Display("w", w)
// Output:
// Display w ():
// w = invalid
}
func Example_ptrToInterface() {
var w io.Writer
Display("&w", &w)
// Output:
// Display &w (*io.Writer):
// (*&w) = nil
}
func Example_struct() {
Display("x", struct{ x interface{} }{3})
// Output:
// Display x (struct { x interface {} }):
// x.x.type = int
// x.x.value = 3
}
func Example_interface() {
var i interface{} = 3
Display("i", i)
// Output:
// Display i (int):
// i = 3
}
func Example_ptrToInterface2() {
var i interface{} = 3
Display("&i", &i)
// Output:
// Display &i (*interface {}):
// (*&i).type = int
// (*&i).value = 3
}
func Example_array() {
Display("x", [1]interface{}{3})
// Output:
// Display x ([1]interface {}):
// x[0].type = int
// x[0].value = 3
}
func Example_movie() {
//!+movie
type Movie struct {
Title, Subtitle string
Year int
Color bool
Actor map[string]string
Oscars []string
Sequel *string
}
//!-movie
//!+strangelove
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. Capt. Lionel Mandrake": "Peter Sellers",
"Pres. Merkin Muffley": "Peter Sellers",
"Gen. Buck Turgidson": "George C. Scott",
"Brig. Gen. Jack D. Ripper": "Sterling Hayden",
`Maj. T.J. "King" Kong`: "Slim Pickens",
},
Oscars: []string{
"Best Actor (Nomin.)",
"Best Adapted Screenplay (Nomin.)",
"Best Director (Nomin.)",
"Best Picture (Nomin.)",
},
}
//!-strangelove
Display("strangelove", strangelove)
// Output:
// Display strangelove (display.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["Gen. Buck Turgidson"] = "George C. Scott"
// strangelove.Actor["Brig. Gen. Jack D. Ripper"] = "Sterling Hayden"
// strangelove.Actor["Maj. T.J. \"King\" Kong"] = "Slim Pickens"
// strangelove.Actor["Dr. Strangelove"] = "Peter Sellers"
// strangelove.Actor["Grp. Capt. Lionel Mandrake"] = "Peter Sellers"
// strangelove.Actor["Pres. Merkin Muffley"] = "Peter Sellers"
// strangelove.Oscars[0] = "Best Actor (Nomin.)"
// strangelove.Oscars[1] = "Best Adapted Screenplay (Nomin.)"
// strangelove.Oscars[2] = "Best Director (Nomin.)"
// strangelove.Oscars[3] = "Best Picture (Nomin.)"
// strangelove.Sequel = nil
}
func Test(t *testing.T) {
// Some other values (YMMV)
Display("os.Stderr", os.Stderr)
// Output:
// Display os.Stderr (*os.File):
// (*(*os.Stderr).file).fd = 2
// (*(*os.Stderr).file).name = "/dev/stderr"
// (*(*os.Stderr).file).nepipe = 0
var w io.Writer = os.Stderr
Display("&w", &w)
// Output:
// Display &w (*io.Writer):
// (*&w).type = *os.File
// (*(*(*&w).value).file).fd = 2
// (*(*(*&w).value).file).name = "/dev/stderr"
// (*(*(*&w).value).file).nepipe = 0
var locker sync.Locker = new(sync.Mutex)
Display("(&locker)", &locker)
// Output:
// Display (&locker) (*sync.Locker):
// (*(&locker)).type = *sync.Mutex
// (*(*(&locker)).value).state = 0
// (*(*(&locker)).value).sema = 0
Display("locker", locker)
// Output:
// Display locker (*sync.Mutex):
// (*locker).state = 0
// (*locker).sema = 0
// (*(&locker)) = nil
locker = nil
Display("(&locker)", &locker)
// Output:
// Display (&locker) (*sync.Locker):
// (*(&locker)) = nil
ips, _ := net.LookupHost("golang.org")
Display("ips", ips)
// Output:
// Display ips ([]string):
// ips[0] = "173.194.68.141"
// ips[1] = "2607:f8b0:400d:c06::8d"
Display("rV", reflect.ValueOf(os.Stderr))
// Output:
// Display rV (reflect.Value):
// (*rV.typ).size = 8
// (*rV.typ).ptrdata = 8
// (*rV.typ).hash = 871609668
// (*rV.typ)._ = 0
// a pointer that points to itself
type P *P
var p P
p = &p
if false {
Display("p", p)
// Output:
// Display p (display.P):
}
// a map that contains itself
type M map[string]M
m := make(M)
m[""] = m
if false {
Display("m", m)
// Output:
// Display m (display.M):
}
// a slice that contains itself
type S []S
s := make(S, 1)
s[0] = s
if false {
Display("s", s)
// Output:
// Display s (display.S):
}
// a linked list that eats its own tail
type Cycle struct {
Value int
Tail *Cycle
}
var c Cycle
c = Cycle{42, &c}
if false {
Display("c", c)
// Output:
// Display c (display.Cycle):
// c.Value = 42
// (*c.Tail).Value = 42
// (*(*c.Tail).Tail).Value = 42
}
}