web-dev-qa-db-ja.com

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, } {
  //do something with the d
}

[]interface{}{ r.a_number, r.a_string, }を達成するためのより良い、より汎用的な方法があるので、各パラメーターを個別にリストする必要はありませんか、あるいは、構造体をループするより良い方法はありますか?

reflect パッケージを調べてみましたが、reflect.ValueOf(*r).Field(0)を取得したらどうするかわからないため、壁にぶつかりました。

ありがとう!

76
omninonsense

Field(i)を使用してフィールドのreflect.Valueを取得した後、Interface()を呼び出すことにより、そこからインターフェイス値を取得できます。このインターフェイス値は、フィールドの値を表します。

ご存知かもしれませんが、goにはジェネリックがないので、フィールドの値を具象型に変換する機能はありません。したがって、そのフィールドのタイプであるTを持つシグネチャGetValue() 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)
}
92
nemo

構造体のフィールドと値を反復処理する場合は、以下の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.を与えます

0
chetan kumar