在Go中遍历结构的字段


107

基本上,(我知道)迭代a的字段值的唯一方法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, } {
  //do something with the d
}

我想知道,是否有更好,更通用的实现方法[]interface{}{ r.a_number, r.a_string, },所以我不需要单独列出每个参数,或者有没有更好的方法遍历结构?

我试图浏览一下reflect包装,但是碰到了墙,因为我不确定一旦取回该怎么办reflect.ValueOf(*r).Field(0)

谢谢!


5
这是一篇有关反射的非常有趣的文章:blog.golang.org/laws-of-reflection以下文章中的一个示例:play.golang.org/p/_bKAQ3dQlu但是请注意,您不能查找未导出的字段与反射包(即以小写字母开头的字段)一起使用
-creack

Answers:


126

reflect.Value使用检索字段的后,Field(i)您可以通过调用从中获取接口值Interface()。然后,所述接口值表示字段的值。

您可能知道,没有函数可以将字段的值转换为具体类型,因为您可能没有泛型。因此,不存在与签名没有功能GetValue() TT被该字段(其改变,当然,这取决于字段)的类型。

您可以在旅途中获得的最接近的是 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)
}

24
是的,因为go不需要泛型。咳嗽,咳嗽:-)有没有一种方法可以得到字段的类型?
U阿瓦洛斯

1
通过reflect.Value.Type(),是的。但请注意,类型并不是go的一等公民,因此您只能使用实例化该类型的新值reflect
nemo

6
v.Field(i).Interface()如果您尝试访问未导出的私有字段,则会发生恐慌。请注意:)
Tarion

10
如果v.Field(i).CanInterface() 未导出字段,使用一个可以避免出现恐慌。
Pedram Esmaeeli

1
如何获得字段名称?
萨瑟什

33

如果要遍历结构的字段和值,则可以使用下面的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())
    }
}

操场上

注意:如果未导出结构体中的字段,v.Field(i).Interface()则将出现恐慌panic: reflect.Value.Interface: cannot return value obtained from unexported field or method.


0

采用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),
    }

    //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"))
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.