web-dev-qa-db-ja.com

インターフェースからすべてのフィールドを取得する

replyオブジェクト/インターフェイスからアクセスできるフィールドを知るにはどうすればよいですか?リフレクションを試しましたが、まずフィールド名を知っておく必要があるようです。利用可能なすべてのフィールドを知る必要がある場合はどうなりますか?

// Do sends a command to the server and returns the received reply.
Do(commandName string, args ...interface{}) (reply interface{}, err error)
9
RAFJR

reflect.TypeOf() 関数を使用して、 _reflect.Type_ 型記述子を取得できます。そこから、インターフェースに格納された動的な値のフィールドをリストできます。

例:

_type Point struct {
    X int
    Y int
}

var reply interface{} = Point{1, 2}
t := reflect.TypeOf(reply)
for i := 0; i < t.NumField(); i++ {
    fmt.Printf("%+v\n", t.Field(i))
}
_

出力:

_{Name:X PkgPath: Type:int Tag: Offset:0 Index:[0] Anonymous:false}
{Name:Y PkgPath: Type:int Tag: Offset:4 Index:[1] Anonymous:false}
_

Type.Field()呼び出しの結果は _reflect.StructField_ 値であり、これはstructであり、とりわけフィールド名が含まれています。

_type StructField struct {
    // Name is the field name.
    Name string
    // ...
}
_

フィールドの値も必要な場合は、 reflect.ValueOf() を使用して reflect.Value() を取得し、次に使用できます。 Value.Field() または Value.FieldByName()

_v := reflect.ValueOf(reply)
for i := 0; i < v.NumField(); i++ {
    fmt.Println(v.Field(i))
}
_

出力:

_1
2
_

Go Playground で試してください。

注:多くの場合、構造体へのポインタはインターフェイスでラップされます。このような場合、Type.Elem()および Value.Elem() を使用して、ポイントされた型または値に「ナビゲート」できます。

_t := reflect.TypeOf(reply).Elem()

v := reflect.ValueOf(reply).Elem()
_

ポインタかどうかわからない場合は、Type.Kind()Value.Kind() を使用して確認し、結果を_reflect.Ptr_と比較できます。 :

_t := reflect.TypeOf(reply)
if t.Kind() == reflect.Ptr {
    t = t.Elem()
}

// ...

v := reflect.ValueOf(reply)
if v.Kind() == reflect.Ptr {
    v = v.Elem()
}
_

Go Playground でこのバリアントを試してください。

Goのリフレクションの詳細については、ブログ投稿 The Laws of Reflection を参照してください。

28
icza