Go语言如何统计一个嵌套结构中的字段数量?

3

有一个结构体CompleteStruct,它由两个嵌套结构体StructAStructB组成,其中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个字段吗?


这里需要使用递归 - 因为您必须考虑嵌入的结构体可能本身具有嵌入的结构体。 - colm.anseo
3个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
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-- // don'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

谢谢你让我走上了正确的道路,但真的需要使用递归吗?请看下面我的答案。 - Eric
根据您的使用情况而定,但通常情况下不会将结构体嵌套多层深。如果您知道结构体不会被嵌套,则无需使用递归。但是,如果它们以任意深度嵌套,则递归是解决问题的方法。 - colm.anseo
reflect.VisibleFields包会将嵌套结构展开。不过,您是否有不使用该包的原因呢? - Eric
再次取决于您的用例:VisibleFields 可能有效,但只会公开“可见”的导出即大写的结构字段名称。它不会包括小写(未导出)的结构字段。因此,如果您只想要导出的字段,则可以使用它。 - colm.anseo

1
< p > 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


0

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

innerFields := 0

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

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

这段代码已经测试过并且可以正常运行


这并不考虑内部字段,它本身嵌入另一个结构。 - colm.anseo

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