英文:
Iterate through the fields of a struct in Go
问题
基本上,我所知道的遍历struct
字段值的唯一方法是这样的:
type Example struct {
a_number uint32
a_string string
}
//...
r := &Example{(2 << 31) - 1, "...."}
for _, d := range []interface{}{r.a_number, r.a_string} {
//对d进行一些操作
}
我想知道是否有更好、更灵活的方法来实现[]interface{}{r.a_number, r.a_string}
,这样我就不需要逐个列出每个参数,或者是否有更好的方法来遍历一个struct
?
我尝试查看了reflect
包,但我遇到了困难,因为我不确定一旦我获取了reflect.ValueOf(*r).Field(0)
后该怎么做。
谢谢!
英文:
Basically, the only way (that I know of) to iterate through the values of the fields of a struct
is like this:
type Example struct {
a_number uint32
a_string string
}
//...
r := &Example{(2 << 31) - 1, "...."}:
for _, d:= range []interface{}{ r.a_number, r.a_string, } {
//do something with the d
}
I was wondering, if there's a better and more versatile way of achieving []interface{}{ r.a_number, r.a_string, }
, so I don't need to list each parameter individually, or alternatively, is there a better way to loop through a struct?
I tried to look through the reflect
package, but I hit a wall, because I'm not sure what to do once I retrieve reflect.ValueOf(*r).Field(0)
.
Thanks!
答案1
得分: 180
在使用Field(i)
获取字段的reflect.Value
之后,你可以通过调用Interface()
方法从中获取一个接口值。该接口值表示字段的值。
由于Go语言中没有泛型,所以没有将字段的值转换为具体类型的函数。因此,没有带有签名GetValue() T
的函数,其中T
是字段的类型(当然,这取决于字段)。
在Go语言中,你可以最接近实现的是GetValue() interface{}
,而这正是reflect.Value.Interface()
提供的功能。
以下代码演示了如何使用反射获取结构体中每个导出字段的值(play链接):
import (
"fmt"
"reflect"
)
func main() {
x := struct{ Foo string; Bar int }{"foo", 2}
v := reflect.ValueOf(x)
values := make([]interface{}, v.NumField())
for i := 0; i < v.NumField(); i++ {
values[i] = v.Field(i).Interface()
}
fmt.Println(values)
}
英文:
After you've retrieved the reflect.Value
of the field by using Field(i)
you can get a
interface value from it by calling Interface()
. Said interface value then represents the
value of the field.
There is no function to convert the value of the field to a concrete type as there are,
as you may know, no generics in go. Thus, there is no function with the signature GetValue() T
with T
being the type of that field (which changes of course, depending on the field).
The closest you can achieve in go is GetValue() interface{}
and this is exactly what reflect.Value.Interface()
offers.
The following code illustrates how to get the values of each exported field in a struct
using reflection (play):
import (
"fmt"
"reflect"
)
func main() {
x := struct{Foo string; Bar int }{"foo", 2}
v := reflect.ValueOf(x)
values := make([]interface{}, v.NumField())
for i := 0; i < v.NumField(); i++ {
values[i] = v.Field(i).Interface()
}
fmt.Println(values)
}
答案2
得分: 103
如果你想遍历结构体的字段和值,你可以参考以下的Go代码:
package main
import (
"fmt"
"reflect"
)
type Student struct {
Fname string
Lname string
City string
Mobile int64
}
func main() {
s := Student{"Chetan", "Kumar", "Bangalore", 7777777777}
v := reflect.ValueOf(s)
typeOfS := v.Type()
for i := 0; i < v.NumField(); i++ {
fmt.Printf("Field: %s\tValue: %v\n", typeOfS.Field(i).Name, v.Field(i).Interface())
}
}
在playground上运行。
注意:如果你的结构体字段没有被导出,那么v.Field(i).Interface()
会引发恐慌panic: reflect.Value.Interface: cannot return value obtained from unexported field or method.
英文:
If you want to Iterate through the Fields and Values of a struct then you can use the below Go code as a reference.
package main
import (
"fmt"
"reflect"
)
type Student struct {
Fname string
Lname string
City string
Mobile int64
}
func main() {
s := Student{"Chetan", "Kumar", "Bangalore", 7777777777}
v := reflect.ValueOf(s)
typeOfS := v.Type()
for i := 0; i< v.NumField(); i++ {
fmt.Printf("Field: %s\tValue: %v\n", typeOfS.Field(i).Name, v.Field(i).Interface())
}
}
Run in playground
Note: If the Fields in your struct are not exported then the v.Field(i).Interface()
will give panic panic: reflect.Value.Interface: cannot return value obtained from unexported field or method.
答案3
得分: 35
Go 1.17(2021年第三季度)应该通过提交009bfea和CL 281233添加一个新选项,修复问题42782。
> ## reflect: 添加VisibleFields函数
>
> 在编写反射结构类型的代码时,通常需要知道完整的结构字段集,包括由于嵌入匿名成员而可用的字段,同时排除因为它们与另一个同名字段处于相同级别而被抹除的字段。
>
> 实现这个逻辑并不复杂,但有点微妙且容易出错。
>
> 这个CL在reflect
包中添加了一个新的reflect.VisibleFields()
函数,它返回适用于给定结构类型的完整字段集。
fields := reflect.VisibleFields(typ)
for j, field := range fields {
...
}
示例:
type employeeDetails struct {
id int16
name string
designation string
}
func structIterator() {
fields := reflect.VisibleFields(reflect.TypeOf(struct{ employeeDetails }{}))
for _, field := range fields {
fmt.Printf("Key: %s\tType: %s\n", field.Name, field.Type)
}
}
英文:
Go 1.17 (Q3 2021) should add a new option, through commit 009bfea and CL 281233, fixing issue 42782.
> ## reflect: add VisibleFields function
>
> When writing code that reflects over a struct type, it's a common requirement to know the full set of struct fields, including fields available due to embedding of anonymous members while excluding fields that are erased because they're at the same level as another field with the same name.
>
> The logic to do this is not that complex, but it's a little subtle and easy to get wrong.
>
> This CL adds a new reflect.VisibleFields()
function to the reflect
package that returns the full set of effective fields that apply in a given struct type.
fields := reflect.VisibleFields(typ)
for j, field := range fields {
...
}
Example,
type employeeDetails struct {
id int16
name string
designation string
}
func structIterator() {
fields := reflect.VisibleFields(reflect.TypeOf(struct{ employeeDetails }{}))
for _, field := range fields {
fmt.Printf("Key: %s\tType: %s\n", field.Name, field.Type)
}
}
答案4
得分: 7
也许有点晚了 :))) 但是还有另一种解决方案,你可以找到结构体的键和值,并对其进行迭代。
package main
import (
"fmt"
"reflect"
)
type person struct {
firsName string
lastName string
iceCream []string
}
func main() {
u := struct {
myMap map[int]int
mySlice []string
myPerson person
}{
myMap: map[int]int{1: 10, 2: 20},
mySlice: []string{"red", "green"},
myPerson: person{
firsName: "Esmaeil",
lastName: "Abedi",
iceCream: []string{"Vanilla", "chocolate"},
},
}
v := reflect.ValueOf(u)
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Type().Field(i).Name)
fmt.Println("\t", v.Field(i))
}
}
并且对于 v.Field(i)
不会出现 panic。
英文:
Maybe too late :))) but there is another solution that you can find the key and value of structs and iterate over that
package main
import (
"fmt"
"reflect"
)
type person struct {
firsName string
lastName string
iceCream []string
}
func main() {
u := struct {
myMap map[int]int
mySlice []string
myPerson person
}{
myMap: map[int]int{1: 10, 2: 20},
mySlice: []string{"red", "green"},
myPerson: person{
firsName: "Esmaeil",
lastName: "Abedi",
iceCream: []string{"Vanilla", "chocolate"},
},
}
v := reflect.ValueOf(u)
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Type().Field(i).Name)
fmt.Println("\t", v.Field(i))
}
}
and there is no *panic* for v.Field(i)
答案5
得分: 0
使用以下代码:
type x struct {
Id int
jsj int
}
func main() {
x2 := x{jsj: 10, Id: 5}
v := reflect.ValueOf(x2)
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Field(i))
}
}
输出:
10
5
英文:
use this:
type x struct {
Id int
jsj int
}
func main() {
x2 := x{jsj: 10, Id: 5}
v := reflect.ValueOf(x2)
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Field(i))
}
}
====>10
====>5
答案6
得分: -1
采用Chetan Kumar的解决方案,如果你需要应用到map[string]int
类型的情况下:
package main
import (
"fmt"
"reflect"
)
type BaseStats struct {
Hp int
HpMax int
Mp int
MpMax int
Strength int
Speed int
Intelligence int
}
type Stats struct {
Base map[string]int
Modifiers []string
}
func StatsCreate(stats BaseStats) Stats {
s := Stats{
Base: make(map[string]int),
}
// 遍历结构体的字段
v := reflect.ValueOf(stats)
typeOfS := v.Type()
for i := 0; i < v.NumField(); i++ {
val := v.Field(i).Interface().(int)
s.Base[typeOfS.Field(i).Name] = val
}
return s
}
func (s Stats) GetBaseStat(id string) int {
return s.Base[id]
}
func main() {
m := StatsCreate(BaseStats{300, 300, 300, 300, 10, 10, 10})
fmt.Println(m.GetBaseStat("Hp"))
}
英文:
Taking Chetan Kumar solution and in case you need to apply to a map[string]int
package main
import (
"fmt"
"reflect"
)
type BaseStats struct {
Hp int
HpMax int
Mp int
MpMax int
Strength int
Speed int
Intelligence int
}
type Stats struct {
Base map[string]int
Modifiers []string
}
func StatsCreate(stats BaseStats) Stats {
s := Stats{
Base: make(map[string]int),
}
//Iterate through the fields of a struct
v := reflect.ValueOf(stats)
typeOfS := v.Type()
for i := 0; i< v.NumField(); i++ {
val := v.Field(i).Interface().(int)
s.Base[typeOfS.Field(i).Name] = val
}
return s
}
func (s Stats) GetBaseStat(id string) int {
return s.Base[id]
}
func main() {
m := StatsCreate(BaseStats{300, 300, 300, 300, 10, 10, 10})
fmt.Println(m.GetBaseStat("Hp"))
}
答案7
得分: -1
使用reflect
包。首先,使用reflect.TypeOf
获取变量的类型,使用reflect.NumField
获取字段的数量。要迭代地获取结构体字段的值,必须使用反射变量并使用函数rg.Elem().Field(i)
。
package main
import (
"fmt"
"reflect"
)
type Gopher struct {
Name string
Color string
Year int
}
func main() {
g := Gopher{Name: "AAA", Color: "BBBB", Year: 2021}
gtype := reflect.TypeOf(g)
numFields := gtype.NumField()
rg := reflect.ValueOf(&g)
for i := 0; i < numFields; i++ {
fmt.Println(rg.Elem().Field(i))
}
}
英文:
Use reflect
package. First, get the type of variable with reflect.TypeOf
and get numbers of elements with reflect.NumField
.To obtain the values of the fields iteratively of a structure must reflect the variable and use the function rg.Elem().Field(i)
package main
import (
"fmt"
"reflect"
)
type Gopher struct {
Name string
Color string
Year int
}
func main() {
g := Gopher{Name: "AAA", Color: "BBBB", Year: 2021}
gtype := reflect.TypeOf(g)
numFields := gtype.NumField()
rg := reflect.ValueOf(&g)
for i := 0; i < numFields; i++ {
fmt.Println(rg.Elem().Field(i))
}
}
答案8
得分: -2
在Go语言中,你可以使用reflect包来遍历结构体的字段。reflect包允许你在运行时检查值的属性,包括它们的类型和值。下面是一个遍历结构体字段的示例:
package main
import (
"fmt"
"reflect"
)
type Movie struct {
Name string
Year int
}
func main() {
p := Movie{"The Dark Knight", 2008}
val := reflect.ValueOf(p)
typ := val.Type()
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
fieldType := typ.Field(i)
fmt.Printf("字段名:%s,字段值:%v\n", fieldType.Name, field.Interface())
}
}
输出结果:
字段名:Name,字段值:The Dark Knight
字段名:Year,字段值:2008
你可以在Go Playground上运行这段代码。
英文:
In Go, you can use the reflect package to iterate through the fields of a struct. The reflect package allows you to inspect the properties of values at runtime, including their type and value. Here's an example of how to iterate through the fields of a struct:
package main
import (
"fmt"
"reflect"
)
type Movie struct {
Name string
Year int
}
func main() {
p := Movie{"The Dark Knight", 2008}
val := reflect.ValueOf(p)
typ := val.Type()
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
fieldType := typ.Field(i)
fmt.Printf("Field Name: %s, Field Value: %v\n", fieldType.Name, field.Interface())
}
}
Output:
Field Name: Name, Field Value: The Dark Knight
Field Name: Age, Field Value: 2008
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论