英文:
Go reflect field index - single index vs. slice
问题
reflect.StructField
的Index
字段的类型是[]int
。关于这一点的文档有些令人困惑:
Index []int // 用于Type.FieldByIndex的索引序列
当然,Type.FieldByIndex
也按预期的方式遵循相同的模式,其行为的解释稍微清晰一些:
// FieldByIndex返回与索引序列对应的嵌套字段。
// 它等效于依次为每个索引i调用Field。
// 如果类型的Kind不是Struct,则会引发panic。
FieldByIndex(index []int) StructField
但是,还有Type.Field()
:
// Field返回结构类型的第i个字段。
// 如果类型的Kind不是Struct,则会引发panic。
// 如果i不在范围[0, NumField())内,则会引发panic。
Field(i int) StructField
因此,它们的行为分别非常清晰。
我的问题是:在哪些字段/什么情况下,reflect.StructField
的Index
会具有len(field.Index) > 1
?这是为了支持枚举嵌入字段(通过父字段中的匿名字段可访问)吗?还会发生在其他情况下吗?(即,可以安全地假设如果!field.Anonymous
,那么我们可以将field.Index[0]
作为Field(i int)
的参数使用吗?)
英文:
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)
?)
答案1
得分: 5
它可以递归地引用嵌入或非嵌入结构体中的字段:
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})) //输出: <main.Foo Value>
fmt.Println(v.FieldByIndex([]int{0, 0})) //输出: foo
}
英文:
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
}
答案2
得分: 1
这是一个例子。为了回答这个问题,我研究了反射测试。
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]
}
这段代码中,我们定义了两个结构体类型:Bar和Foo。Foo嵌入了Bar。在main函数中,我们使用反射获取了Foo类型的反射对象t,并通过FieldByName方法获取了名为"Val"的字段的反射对象f。最后,我们打印了字段f的索引值,结果为[0 0]。
英文:
Here is an example. To answer this question, I've dig into reflect tests.
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]
}
答案3
得分: 1
所以我在寻找这个问题的答案,但实际上我找不到任何东西。为了解释为什么上面的答案不令人满意,我有一个例子:
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
,为什么要使用数组呢?如果它只与其直接父级有关,为什么不存储一个单独的整数?
答案可能比我们(那些对此感到困惑的人)预期的要简单。Index
值通常必须用作FieldByIndex
的参数,因此它被存储在数组中仅仅是为了方便起见。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论