golang诱惑反思 [英] golang recurisive reflection

查看:141
本文介绍了golang诱惑反思的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


我试图递归地反映一个结构,打印出每个字段的类型。如果字段是结构的一部分,我希望能够
标识数组中保存的类型,然后反映该类型。




以下是一些示例代码

  package main 

导入(
log
反映


类型子结构{
名称*字符串
年龄类型
}

类型父结构{
名称字符串
姓氏*字符串
儿童[] *孩子
PetNames []字符串
}

func main(){

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

for i:= 0;我< typ.NumField(); i ++ {
p:= typ.Field(i)
if!p.Anonymous {
switch p.Type.Kind(){
case reflect.Ptr:
log.Printf(Ptr:%s是类型%s,p.Name,p.Type)
案例reflect.Slice:
log.Printf(Slice:%s是类型% s),p.Name,p.Type)
subtyp:= p.Type.Elem()
if subtyp.Kind()== reflect.Ptr {
subtyp = subtyp.Elem ()

log.Printf(\ tDereferenced类型%s,子类型)
默认值:
log.Printf(默认:%s是类型%s ,p.Name,p.Type)
}
}
}

}




输出如下所示:

 这是一个:struct 
默认值:Name是一个字符串
Ptr:Surname是一个类型*字符串
Slice:Children是一个类型[] * main.child
解除引用类型main.child
Slice:PetNames是一个类型[] string
Dereferenced Type string







输出结果是'输入' main.child'



如果我然后尝试反映孩子使用

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

我收到以下内容:

  * reflect.rtype 

如何使用反射API遍历子结构的字段?

解决方案

这是一种方法。

  func printType(前缀字符串,t reflect.Type,访问过的map [reflect.Type] bool){

//打开这个类型的名称(用于描述)
fmt.Printf(%s(,t)

//遍历元素,添加描述为
elems:
用于{
switch t.Kind(){
case reflect.Ptr:
fmt.Print(ptr to)
case reflect.Slice:
fmt.Print(slice of)
case reflect.Array:
fmt.Printf(带有%d个元素的数组,t.Len ))
default:
break elems
}
t = t.Elem()
}

//打印类型
//在struct的情况下,我们打印字段的名称和递归。
switch t.Kind(){
case reflect.Struct :
fmt.Printf(带%d字段的结构)\ n,t.NumField())
if vi位于[t] {
//不要炸毁递归类型定义。
break
}
visited [t] = true
prefix + =
for i:= 0;我< t.NumField();
$ printf(前缀,f.Type,visited)
$($)$ t $ F $
默认值:
fmt.Printf(%s)\\\
,t.Kind())
}
}

func main( ){
printType(,reflect.TypeOf(Parent {}),make(map [reflect.Type] bool))
}
$ b $ p给出了以下类型的Parent {}的输出:

 类型的子结构{
名称*字符串
年龄int
}

类型父结构{
名称字符串
姓氏*字符串
孩子[] *孩子
PetNames []字符串
父母[2] *父母
孩子
}

是:

$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ main.Parent(带有6个字段的结构)
名称字符串(字符串)
姓氏*字符串(ptr到字符串)
儿童[] * main.child(ptr结构片段2个字段)
名称*字符串字符串)
年龄int(int)
PetNames [] string(字符串片段)
Parents [2] * main.Parent(带有2个ptr元素的数组,结构为6个字段)
child main.child(具有2个字段的结构)

游乐场示例


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?

解决方案

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

这篇关于golang诱惑反思的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆