Home  >  Article  >  Backend Development  >  How to Pass Nested Structures by Reference in Reflection and Set Default Values Recursively?

How to Pass Nested Structures by Reference in Reflection and Set Default Values Recursively?

DDD
DDDOriginal
2024-10-24 02:22:29372browse

How to Pass Nested Structures by Reference in Reflection and Set Default Values Recursively?

Passing Nested Structures by Reference through Reflection

Traversing and modifying nested structures through reflection allows for dynamic manipulation of data. However, when encountering a struct field that is itself a struct, setting values using reflection can lead to a "reflect.Value.Set using unaddressable value" panic.

Understanding the Issue

The root of the problem lies in the way reflection handles nested structures. By default, structs are passed by value, which means when we retrieve the Value from a nested struct field for modification, we are operating on a copy of the data rather than the original. Any changes made affect only the copy, not the actual structure.

Solution: Passing by Reference

To set field values of a nested struct, it is necessary to pass it as a pointer. This can be achieved using the Value.Addr() method, which returns a pointer to the actual struct value.

Recursive Default Value Setting

The recursion in the sample code reflects the need to traverse all fields of a struct and its nested structs. To set default values, we call setDefaultValue on the pointer value of each field. For primitive types (int, string, bool), the default values are hardcoded. For nested structs, setDefaultValue is called recursively to handle their fields.

Working Example

Consider the following sample code:

<code class="go">type Client struct {
    Id                int
    Age               int
    PrimaryContact    Contact
    Name              string
}

type Contact struct {
    Id        int
    ClientId  int
    IsPrimary bool
    Email     string
}

func SetDefault(s interface{}) error {
    return setDefaultValue(reflect.ValueOf(s))
}

func setDefaultValue(v reflect.Value) error {

    if v.Kind() != reflect.Ptr {
        return errors.New("Not a pointer value")
    }

    v = reflect.Indirect(v)
    switch v.Kind() {
        case reflect.Int:
            v.SetInt(42)
        case reflect.String:
            v.SetString("Foo")
        case reflect.Bool:
            v.SetBool(true)
        case reflect.Struct:
            // Iterate over the struct fields
            for i := 0; i < v.NumField(); i++ {
                err := setDefaultValue(v.Field(i).Addr())
                if err != nil {
                    return err
                }
            }       

        default:
            return errors.New("Unsupported kind: " + v.Kind().String())

    }

    return nil  
}


func main() {
    a := Client{}
    err := SetDefault(&a)
    if err != nil {
        fmt.Println("Error: ", err)
    } else {
        fmt.Printf("%+v\n", a)
    }
}</code>

Output:

{Id:42 Age:42 PrimaryContact:{Id:42 ClientId:42 IsPrimary:true Email:Foo} Name:Foo}

This example showcases how to pass a nested structure by reference through reflection, setting default values using recursion.

The above is the detailed content of How to Pass Nested Structures by Reference in Reflection and Set Default Values Recursively?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn