リフレクションを使用した値アドレスの取得
インターフェイス上でリフレクションを行うと、そのフィールドを走査できるようになります。ただし、非ポインター フィールドのアドレスを取得するのは困難です。この記事では、ポインターの逆参照の制限を調べることでこの問題に対処し、解決策を紹介します。
問題の概要
次のコードを考えてみましょう:
<code class="go">type Z struct { Id int } type V struct { Id int F Z } type T struct { Id int F V }</code>
関数 InspectStruct は構造体を再帰的に走査し、アドレスを含むそのフィールドの詳細をリストします。簡略化した実装を次に示します。
<code class="go">func InspectStruct(o interface{}) { val := reflect.ValueOf(o) if val.Kind() == reflect.Interface && !val.IsNil() { val = val.Elem() } if val.Kind() == reflect.Ptr { val = val.Elem() } for i := 0; i < val.NumField(); i++ { valueField := val.Field(i) if valueField.Kind() == reflect.Ptr { valueField = valueField.Elem() } address := "not-addressable" if valueField.CanAddr() { address = fmt.Sprint(valueField.Addr().Pointer()) } fmt.Printf("Field Name: %s,\t Field Value: %v,\t Address: %v\n", val.Type().Field(i).Name, valueField.Interface(), address) if valueField.Kind() == reflect.Struct { InspectStruct(valueField.Interface()) } } }</code>
タイプ T のインスタンスでこの関数を実行すると、次の結果が得られます。
Field Name: Id, Field Value: 1, Address: 408125440 Field Name: F, Field Value: {2 {3}}, Address: 408125444 Field Name: Id, Field Value: 2, Address: not-addressable Field Name: F, Field Value: {3}, Address: not-addressable Field Name: Id, Field Value: 3, Address: not-addressable
ご覧のとおり、非ポインター フィールド (「Id」) のアドレスが返されます。
解決策
この問題は、valueField.Interface( )。これはインターフェースを返します。これをフィールド値で使用すると、アドレス情報が失われる可能性があります。
これに対処する修正されたソリューションは次のとおりです。
<code class="go">func InspectStructV(val reflect.Value) { if val.Kind() == reflect.Interface && !val.IsNil() { val = val.Elem() } if val.Kind() == reflect.Ptr { val = val.Elem() } for i := 0; i < val.NumField(); i++ { valueField := val.Field(i) if valueField.Kind() == reflect.Ptr { valueField = valueField.Elem() } address := "not-addressable" if valueField.CanAddr() { address = fmt.Sprintf("0x%X", valueField.Addr().Pointer()) } fmt.Printf("Field Name: %s,\t Field Value: %v,\t Address: %v\n", val.Type().Field(i).Name, valueField.Interface(), address) if valueField.Kind() == reflect.Struct { InspectStructV(valueField) } } } func InspectStruct(v interface{}) { InspectStructV(reflect.ValueOf(v)) }</code>
リフレクトを渡すことによってInspectStructV へのインターフェイスの代わりに .Value{} を使用すると、フィールドのアドレスを正しく取得できます。
結論
を使用して構造体の非ポインタ フィールドを走査する場合、リフレクションでは、valueField.Interface() に依存するのではなく、reflect.Value を保持することが重要です。再帰的 InspectStructV 関数にreflect.Valueを渡すことにより、構造内の任意の深さのフィールドのアドレスを正常に取得できます。
以上がGoでリフレクションを使用して非ポインターフィールドの値アドレスを取得する方法は?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。