Below, we create a function called Display that works like Println but even better: it shows the path traversed along with the value.
e.g.
Display([]string{"hello", "world"})
would print
root.0 = hello
root.1 = world
package main
import (
"fmt"
"reflect"
"strconv"
)
func main() {
Display("hi")
Display([]string{"apple", "banana"})
Display([...]string{"apple", "banana"})
var i interface{} = 3
Display(i)
type astrct struct {
Z string
}
type strct struct {
A string
B int
astrct
}
Display(strct{"js", 1234, astrct{"nodejs"}})
Display(&strct{"js", 1234, astrct{"nodejs"}})
Display(map[string]int{"m1": 1, "m2": 2})
}
func Display(d interface{}) {
fmt.Printf("-- Display for %T --\n", d)
display("root", reflect.ValueOf(d))
}
func display(path string, v reflect.Value) {
switch v.Kind() {
case reflect.Slice, reflect.Array:
for i := 0; i < v.Len(); i++ {
display(fmt.Sprintf("%s.%v", path, i), v.Index(i))
}
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
display(fmt.Sprintf("%s.%s", path, v.Type().Field(i).Name), v.Field(i))
}
case reflect.Ptr:
if v.IsNil() {
fmt.Println("%s = nil", path)
} else {
display(fmt.Sprintf("*%s", path), v.Elem())
}
case reflect.Map:
if v.IsNil() {
fmt.Println("%s = nil", path)
} else {
for _, i := range v.MapKeys() {
display(fmt.Sprintf("%s[%s]", path, i), v.MapIndex(i))
}
}
case reflect.Interface:
display(fmt.Sprintf("%s.value", path), v.Elem())
default:
fmt.Printf("%s = %s\n", path, formatToPrint(v))
}
}
// formatToPrint formats a value without inspecting its internal structure.
func formatToPrint(v reflect.Value) string {
switch k := v.Kind(); {
case k == 0:
return "invalid kind"
case k == 1:
return strconv.FormatBool(v.Bool())
case k >= 2 && k <= 6:
return strconv.FormatInt(v.Int(), 10)
case k >= 7 && k <= 12:
return strconv.FormatUint(v.Uint(), 10)
case k >= 13 && k <= 14:
return strconv.FormatFloat(v.Float(), 'E', -1, 64)
case k >= 15 && k <= 16:
return strconv.FormatComplex(v.Complex(), 'E', -1, 64)
case k == 18 || k == 19 || k == 21 || k == 22 || k == 23:
// reference types:
// chan, func, map, ptr, Slice
return "type=" + v.Type().String() + " 0x" + strconv.FormatUint(uint64(v.Pointer()), 16)
case k == 24:
// string
return strconv.Quote(v.String())
case k == 17 || k == 20 || k == 25:
// aggregate types:
// array, interface, struct
return "type=" + v.Type().String()
case k == 26:
// unsafeptr
return "unsafe ptr"
default:
return "N/A"
}
}
Output from above code =
-- Display for string --
root = "hi"
-- Display for []string --
root.0 = "apple"
root.1 = "banana"
-- Display for [2]string --
root.0 = "apple"
root.1 = "banana"
-- Display for int --
root = 3
-- Display for main.strct --
root.A = "js"
root.B = 1234
root.astrct.Z = "nodejs"
-- Display for *main.strct --
*root.A = "js"
*root.B = 1234
*root.astrct.Z = "nodejs"
-- Display for map[string]int --
root[m1] = 1
root[m2] = 2
Top comments (0)