duanlan5320 2017-12-03 23:05
浏览 70
已采纳

golang递归反射

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条回答 默认 最新

  • dongtie0929 2017-12-04 03:14
    关注

    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)
    ", 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)
    ", 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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器