Golang统计结构体中嵌套结构体的字段数量。

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

Golang count number of fields in a struct of structs

问题

给定一个由两个嵌套结构体StructAStructB组成的结构体CompleteStruct,其中StructB中包含ImbStructC

type StructA struct {
	AA int
	AB int
	AC int
}
type ImbStructC struct {
	BCC int
}
type StructB struct {
	BA int
	BB int
    ImbStructC
}

type CompleteStruct struct {
	StructA
	StructB
}

如何提取内部结构体中的字段总数?

reflect.TypeOf(CompleteStruct{}).NumField())

返回2,我认为是因为CompleteStruct由2个嵌套结构体组成。

我可以使用什么代码来显示CompleteStruct有6个字段?

英文:

Given a struct CompleteStruct that is composed of two embedded structs StructA and StructB where StructB has ImbStructC in it.

type StructA struct {
	AA int
	AB int
	AC int
}
type ImbStructC struct {
	BCC int
}
type StructB struct {
	BA int
	BB int
    ImbStructC
}

type CompleteStruct struct {
	StructA
	StructB
}

How do you extract the total number of fields in the inner struct?

reflect.TypeOf(CompleteStruct{}).NumField())

returns 2, I assume because CompleteStruct is made up of 2 embedded structs.

What code can I use to show that CompleteStruct has 6 fields?

答案1

得分: 1

递归是解决这个问题的方法,因为嵌套的结构字段可能本身嵌套了另一个结构。

此外,我们应该小心不要将嵌套的结构计算为字段 - 在reflect包中,它们被列为“匿名”字段:

func countFields(v any) int {
    return rvCountFields(reflect.ValueOf(v))
}

func rvCountFields(rv reflect.Value) (count int) {

    if rv.Kind() != reflect.Struct {
        return
    }

    fs := rv.NumField()
    count += fs

    for i := 0; i < fs; i++ {
        f := rv.Field(i)
        if rv.Type().Field(i).Anonymous {
            count-- // 不要将嵌套的结构(列为匿名字段)计算为字段
        }

        // 递归每个字段,看看该字段是否也是一个嵌套的结构
        count += rvCountFields(f)
    }

    return
}

输出:

main.CompleteStruct : count = 5
main.StructA        : count = 3
main.StructB        : count = 2
main.StructC        : count = 6
main.StructD        : count = 12
main.Empty          : count = 0
int                 : count = 0
英文:

Recursion is needed to solve this, as an embedded struct field may itself embed another struct.

Also, one should be careful not to count embedded structs as field - these are listed as "anonymous" fields in the reflect package:

func countFields(v any) int {
	return rvCountFields(reflect.ValueOf(v))
}

func rvCountFields(rv reflect.Value) (count int) {

	if rv.Kind() != reflect.Struct {
		return
	}

	fs := rv.NumField()
	count += fs

	for i := 0; i &lt; fs; i++ {
		f := rv.Field(i)
		if rv.Type().Field(i).Anonymous {
			count-- // don&#39;t count embedded structs (listed as anonymous fields) as a field
		}

		// recurse each field to see if that field is also an embedded struct
		count += rvCountFields(f)
	}

	return
}

https://go.dev/play/p/IjOllo86_xk

Output:

main.CompleteStruct : count = 5
main.StructA        : count = 3
main.StructB        : count = 2
main.StructC        : count = 6
main.StructD        : count = 12
main.Empty          : count = 0
int                 : count = 0

答案2

得分: 1

reflect.VisibleFields包列出了结构体中的所有字段,然后只需计算那些非匿名字段的数量。

func CountNumberOfFieldsInAStruct(obj interface{}) int {
	fields := reflect.VisibleFields(reflect.TypeOf(obj))
	count := 0
	for _, field := range fields {
		if !field.Anonymous {
			count += 1
		}
	}
	return count
}

正如@colm.anseo提到的,“这只会公开“可见”的即大写的结构体字段名。它不会包括小写(未公开)的结构体字段。所以如果你只想要公开的字段,那么这个方法可以工作”。

在这里进行了测试

https://go.dev/play/p/Ea-y8YAkcqZ

英文:

The reflect.VisibleFields package lists all the fields in the struct, from there is "just" a matter of counting those fields that are not Anonymous.

func CountNumberOfFieldsInAStruct(obj interface{}) int {
	fields := reflect.VisibleFields(reflect.TypeOf(obj))
	count := 0
	for _, field := range fields {
		if !field.Anonymous {
			count += 1
		}
	}
	return count
}

As @colm.anseo mentions "this will only expose the "visible" exported i.e. capitalized struct field names. It will not include lowercase (unexported) struct fields. So if you only want exported fields, then this would work"

Tested here

https://go.dev/play/p/Ea-y8YAkcqZ

答案3

得分: 0

基本上,你需要从父结构体中获取字段的数量,然后循环遍历子结构体并获取每个子结构体的字段数量,然后将它们相加。

innerFields := 0

numOfFields := reflect.TypeOf(CompleteStruct{}).NumField()

for i := 0; i < numOfFields; i++ {
    innerFields += reflect.TypeOf(CompleteStruct{}).Field(i).Type.NumField()
}

这段代码已经经过测试并且可以正常工作。

英文:

Basically you need to get the number of fields from the parent struct and then loop through the children and get the number of fields for each child and then add them up

innerFields := 0

numOfFields := reflect.TypeOf(CompleteStruct{}).NumField()

for i := 0; i &lt; numOfFields; i++ {
	innerFields += reflect.TypeOf(CompleteStruct{}).Field(i).Type.NumField()
}

This code is tested and works

huangapple
  • 本文由 发表于 2022年9月24日 22:30:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/73838001.html
匿名

发表评论

匿名网友

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

确定