如何在Golang中反映结构体递归

5

我想递归地反映结构类型和值,但是失败了。我不知道如何递归传递子结构。

它会出现以下错误。

panic: reflect: NumField of non-struct type

goroutine 1 [running]:
reflect.(*rtype).NumField(0xc0b20, 0xc82000a360)
    /usr/local/go/src/reflect/type.go:660 +0x7b

我有两个结构体PersonName

type Person struct {
    Fullname NameType
    Sex      string
}

type Name struct {
    Firstname string
    Lastname  string
}

我在main函数中定义了一个名为Person的结构体,并使用递归函数展示了该结构体。
person := Person{
    Name{"James", "Bound"},
    "Male",
}

display(&person)

display函数递归显示结构体。

func display(s interface{}) {
    reflectType := reflect.TypeOf(s).Elem()
    reflectValue := reflect.ValueOf(s).Elem()

    for i := 0; i < reflectType.NumField(); i++ {
        typeName := reflectType.Field(i).Name

        valueType := reflectValue.Field(i).Type()
        valueValue := reflectValue.Field(i).Interface()

        switch reflectValue.Field(i).Kind() {
        case reflect.String:
            fmt.Printf("%s : %s(%s)\n", typeName, valueValue, valueType)
        case reflect.Int32:
            fmt.Printf("%s : %i(%s)\n", typeName, valueValue, valueType)
        case reflect.Struct:
            fmt.Printf("%s : it is %s\n", typeName, valueType)
            display(&valueValue)
        }

    }
}

请查看此链接以获取解决方案:https://dev59.com/nILba4cB1Zd3GeqPYwjf - Prashant Thakkar
如果您不想自己完成此操作,或想看看其他人如何完成,请查看这个非常好的 Go 代码美化工具https://github.com/davecgh/go-spew。 - FuriousGeorge
1个回答

7

在你的display函数中,你将valueValue声明为:

valueValue := reflectValue.Field(i).Interface()

因此,valueValue 的类型为 interface{}。在 for 循环内部,你有一个对 display 的递归调用:

display(&valueValue)

因此,它被调用时的参数类型为*interface{}。在递归调用中,reflectType将代表interface{}而不是存储在值中的类型。由于NumField只能在表示结构体的reflect.Type上调用,因此会导致恐慌。
如果您想使用指向结构体的指针调用display函数,可以像这样做:
v := valueValue := reflectValue.Field(i).Addr()
display(v.Interface())

@没错,我很困惑反射。有reflect.TypeOf、reflect.ValueOf等很多方法。我需要更多时间来研究它们。 :) - firelyu
在“display”函数内修改结构值是否可能?@James Henstridge - Angger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接