DEV Community

HM
HM

Posted on

2 2 1 1 1

go.reflect for a custom Print function

#go

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"
    }
}

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

AWS Q Developer image

Your AI Code Assistant

Generate and update README files, create data-flow diagrams, and keep your project fully documented. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay