mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-09-13 15:12:32 +00:00
good good study, day day up!
This commit is contained in:
90
vendor/gopl.io/ch12/display/display.go
generated
vendored
Normal file
90
vendor/gopl.io/ch12/display/display.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
// 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
|
259
vendor/gopl.io/ch12/display/display_test.go
generated
vendored
Normal file
259
vendor/gopl.io/ch12/display/display_test.go
generated
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package display
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"gopl.io/ch7/eval"
|
||||
)
|
||||
|
||||
// NOTE: we can't use !+..!- comments to excerpt these tests
|
||||
// into the book because it defeats the Example mechanism,
|
||||
// which requires the // Output comment to be at the end
|
||||
// of the function.
|
||||
|
||||
func Example_expr() {
|
||||
e, _ := eval.Parse("sqrt(A / pi)")
|
||||
Display("e", e)
|
||||
// Output:
|
||||
// Display e (eval.call):
|
||||
// e.fn = "sqrt"
|
||||
// e.args[0].type = eval.binary
|
||||
// e.args[0].value.op = 47
|
||||
// e.args[0].value.x.type = eval.Var
|
||||
// e.args[0].value.x.value = "A"
|
||||
// e.args[0].value.y.type = eval.Var
|
||||
// e.args[0].value.y.value = "pi"
|
||||
}
|
||||
|
||||
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 (<nil>):
|
||||
// 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)
|
||||
|
||||
// We don't use an Output: comment since displaying
|
||||
// a map is nondeterministic.
|
||||
/*
|
||||
//!+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
|
||||
//!-output
|
||||
*/
|
||||
}
|
||||
|
||||
// This test ensures that the program terminates without crashing.
|
||||
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"
|
||||
|
||||
// Even metarecursion! (YMMV)
|
||||
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):
|
||||
// ...stuck, no output...
|
||||
}
|
||||
|
||||
// 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):
|
||||
// ...stuck, no output...
|
||||
}
|
||||
|
||||
// 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):
|
||||
// ...stuck, no output...
|
||||
}
|
||||
|
||||
// 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
|
||||
// ...ad infinitum...
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user