reflect.StructField has an Index field that is typed []int. The documentation on this is slightly confounding:
Index []int // index sequence for Type.FieldByIndex
And of course Type.FieldByIndex follows suit as expected, with the somewhat clearer explanation of its behavior:
// FieldByIndex returns the nested field corresponding
// to the index sequence. It is equivalent to calling Field
// successively for each index i.
// It panics if the type's Kind is not Struct.
FieldByIndex(index []int) StructField
But, there is also Type.Field():
// Field returns a struct type's i'th field.
// It panics if the type's Kind is not Struct.
// It panics if i is not in the range [0, NumField()).
Field(i int) StructFiel
So the behavior of those respectively is very clear.
My question: Exactly for which fields / what circumstances will a reflect.StructField have an Index with len(field.Index) > 1? Is this there to support enumerating embedded fields (reachable through an anonymous field in the parent)? Does it happen in other cases? (ie. is it safe to assume if !field.Anonymous, then we can just use field.Index[0] as an argument to Field(i int)?)
It can refer to fields in embedded or non embedded structs, recursively:
type Foo struct {
Bar string
}
type Baz struct {
Zoo Foo
}
func main() {
b := Baz{Zoo:Foo{"foo"}}
v := reflect.ValueOf(b)
fmt.Println(v.FieldByIndex([]int{0})) //output: <main.Foo Value>
fmt.Println(v.FieldByIndex([]int{0, 0})) //output: foo
}
So I was looking for the answer to this question, and I really haven't been able to find anything. To explain why the answer above is not satisfactory, I have an example:
package main
import (
"fmt"
"reflect"
)
type (
A struct {
W int
X int
}
B struct {
Y int
A A
}
C struct {
B B
Z int
}
)
func main() {
b := B{1, A{2, 3}}
c := C{b, 4}
bt := reflect.TypeOf(b)
ct := reflect.TypeOf(c)
ba := bt.FieldByIndex([]int{1, 0})
ca := ct.FieldByIndex([]int{0, 1, 0})
fmt.Println("B > A = ", ba.Index)
fmt.Println("C > B > A = ", ca.Index)
}
The output is:
B > A = [0]
C > B > A = [0]
So with the description of StructField.Index as is given in the docs (
Index []int // index sequence for Type.FieldByIndex
) one would assume the output would correspond in some way to retrieving the same field via the FieldByIndex method, and since that is designed for nested fields, the output above might be confusing. If the Index is always an []int of length 1, why even use an array? Why does it not store a single int if it is only in relation to its immediate parent?
The answer is probably simpler than we (those of us who found this confusing) expected. The Index value must often be used as an argument for FieldByIndex, and so it is stored in an array simply for convenience.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With