Go 反映字段索引 - 单个索引与切片
Go reflect field index - single index vs. slice
reflect.StructField
有一个输入 []int
的 Index
字段。关于这个的文档有点混乱:
Index []int // index sequence for Type.FieldByIndex
当然 Type.FieldByIndex
也如预期的那样效仿,对其行为的解释更加清晰:
// 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
但是,还有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
所以他们各自的行为非常清楚。
我的问题:reflect.StructField
的 Index
和 len(field.Index) > 1
究竟针对哪些字段/什么情况?这是否支持枚举嵌入式字段(可通过父级中的匿名字段访问)?在其他情况下会发生吗? (即假设 !field.Anonymous
是否安全,那么我们可以只使用 field.Index[0]
作为 Field(i int)
的参数?)
它可以递归地引用嵌入或非嵌入结构中的字段:
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
}
这是一个例子。为了回答这个问题,我深入研究了反射测试。
package main
import (
"fmt"
"reflect"
)
type (
Bar struct {
Val string
}
Foo struct {
Bar
}
)
func main() {
t := reflect.TypeOf(Foo{})
f, _ := t.FieldByName("Val")
fmt.Println(f.Index) // [0 0]
}
所以我一直在寻找这个问题的答案,但我真的找不到任何东西。为了解释为什么上面的答案不尽如人意,我举个例子:
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)
}
输出为:
B > A = [0]
C > B > A = [0]
因此,根据文档中对 StructField.Index 的描述(
Index []int // index sequence for Type.FieldByIndex
) 人们会假设输出会以某种方式对应于通过 FieldByIndex
方法检索相同的字段,并且由于它是为嵌套字段设计的,所以上面的输出可能会令人困惑。如果 Index
始终是长度为 1 的 []int
,为什么还要使用数组?如果它仅与其直接父级相关,为什么它不存储单个 int?
答案可能比我们(我们这些感到困惑的人)预期的要简单。 Index
值必须经常用作 FieldByIndex
的参数,因此为了方便起见,它存储在数组中。
reflect.StructField
有一个输入 []int
的 Index
字段。关于这个的文档有点混乱:
Index []int // index sequence for Type.FieldByIndex
当然 Type.FieldByIndex
也如预期的那样效仿,对其行为的解释更加清晰:
// 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
但是,还有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
所以他们各自的行为非常清楚。
我的问题:reflect.StructField
的 Index
和 len(field.Index) > 1
究竟针对哪些字段/什么情况?这是否支持枚举嵌入式字段(可通过父级中的匿名字段访问)?在其他情况下会发生吗? (即假设 !field.Anonymous
是否安全,那么我们可以只使用 field.Index[0]
作为 Field(i int)
的参数?)
它可以递归地引用嵌入或非嵌入结构中的字段:
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
}
这是一个例子。为了回答这个问题,我深入研究了反射测试。
package main
import (
"fmt"
"reflect"
)
type (
Bar struct {
Val string
}
Foo struct {
Bar
}
)
func main() {
t := reflect.TypeOf(Foo{})
f, _ := t.FieldByName("Val")
fmt.Println(f.Index) // [0 0]
}
所以我一直在寻找这个问题的答案,但我真的找不到任何东西。为了解释为什么上面的答案不尽如人意,我举个例子:
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)
}
输出为:
B > A = [0]
C > B > A = [0]
因此,根据文档中对 StructField.Index 的描述(
Index []int // index sequence for Type.FieldByIndex
) 人们会假设输出会以某种方式对应于通过 FieldByIndex
方法检索相同的字段,并且由于它是为嵌套字段设计的,所以上面的输出可能会令人困惑。如果 Index
始终是长度为 1 的 []int
,为什么还要使用数组?如果它仅与其直接父级相关,为什么它不存储单个 int?
答案可能比我们(我们这些感到困惑的人)预期的要简单。 Index
值必须经常用作 FieldByIndex
的参数,因此为了方便起见,它存储在数组中。