ホームページ >バックエンド開発 >Golang >Goでリフレクションを使用して非ポインターフィールドの値アドレスを取得する方法は?

Goでリフレクションを使用して非ポインターフィールドの値アドレスを取得する方法は?

DDD
DDDオリジナル
2024-10-29 19:35:02835ブラウズ

How to Retrieve the Value Address of Non-Pointer Fields Using Reflection in Go?

リフレクションを使用した値アドレスの取得

インターフェイス上でリフレクションを行うと、そのフィールドを走査できるようになります。ただし、非ポインター フィールドのアドレスを取得するのは困難です。この記事では、ポインターの逆参照の制限を調べることでこの問題に対処し、解決策を紹介します。

問題の概要

次のコードを考えてみましょう:

<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 サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。