Home > Software engineering >  Golang count number of fields in a struct of structs
Golang count number of fields in a struct of structs

Time:09-27

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?

CodePudding user response:

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

CodePudding user response:

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 < numOfFields; i   {
    innerFields  = reflect.TypeOf(CompleteStruct{}).Field(i).Type.NumField()
}

This code is tested and works

CodePudding user response:

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

  • Related