golang recurisive reflection

試著忘記壹切 提交于 2020-01-05 05:54:51

问题


I am trying to reflect recursively over a struct, printing out the type of each field. Where a field is an slice of structs, I'd like to be able to identify the type held in the array and then reflect over that type.

Here is some sample code

package main

import (
    "log"
    "reflect"
)

type child struct {
    Name *string
    Age  int
}

type Parent struct {
    Name     string
    Surname  *string
    Children []*child
    PetNames []string
}

func main() {

    typ := reflect.TypeOf(Parent{})
    log.Printf("This is a : %s", typ.Kind())

    for i := 0; i < typ.NumField(); i++ {
        p := typ.Field(i)
        if !p.Anonymous {
            switch p.Type.Kind() {
            case reflect.Ptr:
                log.Printf("Ptr: %s is a type %s", p.Name, p.Type)
            case reflect.Slice:
                log.Printf("Slice: %s is a type %s", p.Name, p.Type)
                subtyp := p.Type.Elem()
                if subtyp.Kind() == reflect.Ptr {
                    subtyp = subtyp.Elem()
                }
                log.Printf("\tDereferenced Type%s", subtyp)
            default:
                log.Printf("Default: %s is a type %s", p.Name, p.Type)
            }
        }
    }

}

The output looks like this:

This is a : struct
Default: Name is a type string
Ptr: Surname is a type *string
Slice: Children is a type []*main.child
    Dereferenced Type main.child
Slice: PetNames is a type []string
    Dereferenced Type string

When I identify that a field type is a slice of pointers, I am able to infer the type by calling subtype.Elem().

The output is 'main.child'

If I then try to reflect child using

subSubType := reflect.TypeOf(subtyp)
log.Printf("%+v", subSubType) 

I get the following:

 *reflect.rtype

How can I use the reflection API to iterate over the fields of the child struct?


回答1:


Here's one way to do it.

func printType(prefix string, t reflect.Type, visited map[reflect.Type]bool) {

    // Print the name of this type with opening ( for description.
    fmt.Printf("%s (", t)

    // Traverse elements, adding to description as we go.
elems:
    for {
        switch t.Kind() {
        case reflect.Ptr:
            fmt.Print("ptr to ")
        case reflect.Slice:
            fmt.Print("slice of ")
        case reflect.Array:
            fmt.Printf("array with %d elements of ", t.Len())
        default:
            break elems
        }
        t = t.Elem()
    }

    // Print the kind of the type and the closing ) of the description.
    // In the case of a struct, we print the names of the fields and recurse.
    switch t.Kind() {
    case reflect.Struct:
        fmt.Printf("struct with %d fields)\n", t.NumField())
        if visited[t] {
            // Don't blow up on recursive type definition.
            break
        }
        visited[t] = true
        prefix += "    "
        for i := 0; i < t.NumField(); i++ {
            f := t.Field(i)
            fmt.Print(prefix, f.Name, " ")
            printType(prefix, f.Type, visited)
        }
    default:
        fmt.Printf("%s)\n", t.Kind())
    }
}

func main() {
    printType("", reflect.TypeOf(Parent{}), make(map[reflect.Type]bool))
}

The output for Parent{} given the following types:

type child struct {
    Name *string
    Age  int
}

type Parent struct {
    Name     string
    Surname  *string
    Children []*child
    PetNames []string
    Parents  [2]*Parent
    child
}

is:

main.Parent (struct with 6 fields)
    Name string (string)
    Surname *string (ptr to string)
    Children []*main.child (slice of ptr to struct with 2 fields)
        Name *string (ptr to string)
        Age int (int)
    PetNames []string (slice of string)
    Parents [2]*main.Parent (array with 2 elements of ptr to struct with 6 fields)
    child main.child (struct with 2 fields)

playground example



来源:https://stackoverflow.com/questions/47624318/golang-recurisive-reflection

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!