如何在Golang中实现递归结构体的反射?

huangapple go评论86阅读模式
英文:

How to reflect struct recursive in golang

问题

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

它报错如下:

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
}

我在主函数中定义了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)
		}

	}
}
英文:

I want to reflect the struct type and value recursively, but it fails. I don't know how to pass the sub struct recursively.

It error the following.

panic: reflect: NumField of non-struct type

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

I have two struct Person and Name

type Person struct {
	Fullname NameType
	Sex      string
}

type Name struct {
	Firstname string
	Lastname  string
}

I define the Person in main, and display the struct with recursive function.

person := Person{
    Name{&quot;James&quot;, &quot;Bound&quot;},
	&quot;Male&quot;,
}

display(&amp;person)

The display function recursive display the struct.

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

	for i := 0; i &lt; 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(&quot;%s : %s(%s)\n&quot;, typeName, valueValue, valueType)
		case reflect.Int32:
			fmt.Printf(&quot;%s : %i(%s)\n&quot;, typeName, valueValue, valueType)
		case reflect.Struct:
			fmt.Printf(&quot;%s : it is %s\n&quot;, typeName, valueType)
			display(&amp;valueValue)
		}

	}
}

答案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())
英文:

Inside your display function, you declare valueValue as:

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

So valueValue is of type interface{}. Inside the for loop, you have a recursive call to display:

display(&amp;valueValue)

So it is being called with an argument of type *interface{}. Inside the recursive call, reflectType will represent interface{} rather than the type that happens to be stored within the value. Since NumField can only be called on reflect.Type's representing structs, you get a panic.

If you want to call display with a pointer to the struct instead, you could do so with something like this:

v := valueValue := reflectValue.Field(i).Addr()
display(v.Interface())

huangapple
  • 本文由 发表于 2015年12月28日 19:54:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/34493062.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定