사용자 지정 인쇄 기능에 대한 go.reflect

17640 단어 go
아래에서 Println처럼 작동하지만 더 나은 기능인 Display라는 함수를 만듭니다. 이 함수는 값과 함께 이동한 경로를 보여줍니다.

예를 들어Display([]string{"hello", "world"})인쇄 할 것root.0 = helloroot.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"
    }
}



위 코드의 출력 =

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

좋은 웹페이지 즐겨찾기