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