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記事の例の1つに従います。リフレクトパッケージ(小文字で始まるフィールド)で
2013

回答:


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 Avalos 2017年

1
を介してreflect.Value.Type()、はい。ただし、型はgoの第一級市民ではないため、を使用してインスタンス化できるのはその型の新しい値のみreflectです。
nemo 2017年

6
v.Field(i).Interface()エクスポートされていないプライベートフィールドにアクセスしようとすると、パニックが発生します。注意してください:)
タリオン

10
v.Field(i).CanInterface() エクスポートされていないフィールドの場合、これを使用するとパニックを回避できます。
Pedram Esmaeeli

1
フィールド名を取得するにはどうすればよいですか?
Sathesh

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

撮影チェッタン・クマールのソリューションを、ケースには、あなたは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"))
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.