mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2024-11-24 15:18:57 +00:00
91 lines
2.3 KiB
Go
91 lines
2.3 KiB
Go
|
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||
|
|
||
|
// See page 333.
|
||
|
|
||
|
// Package display provides a means to display structured data.
|
||
|
package display
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"reflect"
|
||
|
"strconv"
|
||
|
)
|
||
|
|
||
|
//!+Display
|
||
|
|
||
|
func Display(name string, x interface{}) {
|
||
|
fmt.Printf("Display %s (%T):\n", name, x)
|
||
|
display(name, reflect.ValueOf(x))
|
||
|
}
|
||
|
|
||
|
//!-Display
|
||
|
|
||
|
// formatAtom formats a value without inspecting its internal structure.
|
||
|
// It is a copy of the the function in gopl.io/ch11/format.
|
||
|
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)
|
||
|
// ...floating-point and complex cases omitted for brevity...
|
||
|
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"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//!+display
|
||
|
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))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//!-display
|