递归扩展包含指针的结构定义

时间:2018-10-08 12:42:54

标签: go reflection

此问题基于以下内容: go reflection deeply in struct 我需要做同样的事情-扩展结构定义以将其作为JSON对象传递,但唯一不同的是结构包含指向另一个结构的指针。因此,提供的代码无法处理该问题。我试图通过以下方式对其进行修改:

func printFields(prefix string, t reflect.Type) {
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        fmt.Printf("%v%v %v\n", prefix, f.Name, f.Type)
        if f.Type.Kind() == reflect.Struct {
            fmt.Println(reflect.New(f.Type))
            printFields(fmt.Sprintf("  %v", prefix), f.Type)
        } else if f.Type.Kind() == reflect.Ptr {
            fmt.Println("type ", f.Type )
            printFields(fmt.Sprintf("  %v", prefix), f.Type)
        }
    }
}

但是在出现指针的情况下会感到恐慌。如何解决?

编辑: 得到了我需要的东西:

func printFields(prefix string, t reflect.Type) {
    if t.Kind() != reflect.Struct {
        return
    }
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        fmt.Printf("%v%v %v\n", prefix, f.Name, f.Type)
        if f.Type.Kind() == reflect.Struct {
            fmt.Println(reflect.New(f.Type))
            printFields(fmt.Sprintf("  %v", prefix), f.Type)
        } else if f.Type.Kind() == reflect.Ptr {
            printFields(fmt.Sprintf("  %v", prefix), f.Type.Elem())
        }
    }
}

func printExpandedStruct(s interface{}) {
    printFields("", reflect.ValueOf(s).Type())
}

1 个答案:

答案 0 :(得分:1)

如果字段类型是指针,则使用指针的元素类型。否则,逻辑与链接问题中的逻辑相同。

func printFields(prefix string, t reflect.Type) {
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        fmt.Printf("%v%v %v\n", prefix, f.Name, f.Type)
        ft := f.Type
        if ft.Kind() == reflect.Ptr {
            ft = ft.Elem()
        }
        if ft.Kind() == reflect.Struct {
            printFields(fmt.Sprintf("  %v", prefix), ft)
        }
    }
}

Run it on the playground

下面的代码处理更一般的情况,其中字段可以是数组,切片,通道,指针或这些类型的组合。

func printFields(prefix string, t reflect.Type) {
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        fmt.Printf("%v%v %v\n", prefix, f.Name, f.Type)
        ft := f.Type
        for ft.Kind() == reflect.Ptr ||
            ft.Kind() == reflect.Slice ||
            ft.Kind() == reflect.Array ||
            ft.Kind() == reflect.Chan {
            ft = ft.Elem()
        }
        if ft.Kind() == reflect.Struct {
            printFields(fmt.Sprintf("  %v", prefix), ft)
        }
    }
}

Run it on the playground