Maison >développement back-end >Golang >Comment récupérer l'adresse de valeur des champs sans pointeur à l'aide de Reflection in Go ?

Comment récupérer l'adresse de valeur des champs sans pointeur à l'aide de Reflection in Go ?

DDD
DDDoriginal
2024-10-29 19:35:02835parcourir

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

Récupération de l'adresse de valeur à l'aide de la réflexion

Réfléchir sur une interface permet de parcourir ses champs. Cependant, obtenir l’adresse d’un champ non pointeur présente un défi. Cet article aborde ce problème en examinant les limites du déréférencement de pointeur et présente une solution.

Aperçu du problème

Considérez le code suivant :

<code class="go">type Z struct {
    Id int
}

type V struct {
    Id int
    F Z
}

type T struct {
    Id int
    F V
}</code>

La fonction InspectStruct parcourt récursivement une structure et répertorie les détails de ses champs, y compris l'adresse. Voici une implémentation simplifiée :

<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>

L'exécution de cette fonction sur une instance de type T donne :

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

Comme vous pouvez le constater, les adresses des champs non pointeurs ("Id" et "F" de type "Z" et "V") ne sont pas accessibles.

Solution

Le problème vient du déréférencement de la valeur obtenue à partir de valueField.Interface( ). Cela renvoie une interface{} qui, lorsqu'elle est utilisée dans une valeur de champ, peut entraîner la perte des informations d'adresse.

Voici une solution modifiée qui résout ce problème :

<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>

En passant un reflet .Value au lieu d'une interface{} vers InspectStructV, l'adresse du champ peut être obtenue correctement.

Conclusion

Lors du parcours de champs non pointeurs dans une structure en utilisant réflexion, il est crucial de préserver la réflexion.Value au lieu de s'appuyer sur valueField.Interface(). En passant Reflect.Value à la fonction récursive InspectStructV, vous pouvez récupérer avec succès les adresses des champs à n'importe quelle profondeur de la structure.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn