英文:
Getting substruct field in Go
问题
我正在尝试使用反射从struct
值中获取字段。
package main
import (
"fmt"
"reflect"
)
type Vertex struct {
X string
Y string
SubVertex SubVertex
}
type SubVertex struct {
Z string
}
func get_field(v Vertex, field string) string {
r := reflect.ValueOf(v)
f := reflect.Indirect(r).FieldByName(field)
return f.String()
}
func main() {
v := Vertex{"a", "b", SubVertex{"c"}}
fmt.Println(get_field(v, "X"))
fmt.Println(get_field(v, "Y"))
fmt.Println(get_field(v, "Z")) // Invalid Value
}
在第三个案例中,当我尝试获取Z
字段的值时,我得到了Invalid Value。如果SubVertex
是一个匿名字段,这将起作用,但我需要使用一个命名字段。
我该如何使其工作?
英文:
I am trying to get fields from a struct
value using reflection.
package main
import (
"fmt"
"reflect"
)
type Vertex struct {
X string
Y string
SubVertex SubVertex
}
type SubVertex struct {
Z string
}
func get_field(v Vertex, field string) string {
r := reflect.ValueOf(v)
f := reflect.Indirect(r).FieldByName(field)
return f.String()
}
func main() {
v := Vertex{"a", "b", SubVertex{"c"}}
fmt.Println(get_field(v, "X"))
fmt.Println(get_field(v, "Y"))
fmt.Println(get_field(v, "Z")) // Invalid Value
}
I get Invalid Value in the third case, when I try to get the value of the Z
field. If SubVertex
were an anonymous field, this would work, but I need to use a named field.
How do I make this work?
答案1
得分: 4
在这种情况下,您必须像正常访问值一样使用reflect包。所以
v.X // a
v.Y // b
v.SubVertex.Z // c
变成了
r := reflect.ValueOf(v)
x := reflect.Indirect(r).FieldByName("X")
x.String() // a
...
z := reflect.Indirect(r).FieldByName("SubVertex").FieldByName("Z")
z.String() // c
请注意,FieldByName()
在 Value
上调用并返回一个 Value
,因此它的工作方式与正常访问相同。还请注意,根据文档:
> Indirect返回v指向的值。如果v是nil指针,则Indirect返回零值。如果v不是指针,则Indirect返回v。
因此,对Indirect()
的调用将是一个无操作,但如果您决定在将来给它一个指针,它将保护它免受崩溃的影响。
至于您的函数,可以这样实现:
func get_field(v Vertex, field string) string {
r := reflect.ValueOf(v)
if field == "Z" {
f := reflect.Indirect(r).FieldByName("SubVertex").FieldByName(field)
return f.String()
}
f := reflect.Indirect(r).FieldByName(field)
return f.String()
}
链接:https://play.golang.org/p/eZyTl8OSTZ
英文:
In this case, you have to use the reflect package in the same manner as you would accessing the values normally. So
v.X // a
v.Y // b
v.SubVertex.Z // c
becomes
r := reflect.ValueOf(v)
x := reflect.Indirect(r).FieldByName("X")
x.String() // a
...
z := reflect.Indirect(r).FieldByName("SubVertex").FieldByName("Z")
z.String() // c
Note that FieldByName()
is called on a Value
and returns a Value
, so it works much the same as just accessing it regularly. Also note that as per the documentation:
> Indirect returns the value that v points to. If v is a nil pointer, Indirect returns a zero Value. If v is not a pointer, Indirect returns v.
So the call to Indirect()
would be a No-op, but would protect it from having a meltdown if you decided to give it a pointer in the future.
As for your function, this would work
func get_field(v Vertex, field string) string {
r := reflect.ValueOf(v)
if field == "Z" {
f := reflect.Indirect(r).FieldByName("SubVertex").FieldByName(field)
return f.String()
}
f := reflect.Indirect(r).FieldByName(field)
return f.String()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论