Home  >  Article  >  Backend Development  >  How Can We Modify Nested Struct Fields Using Reflection to Achieve Persistence?

How Can We Modify Nested Struct Fields Using Reflection to Achieve Persistence?

Susan Sarandon
Susan SarandonOriginal
2024-10-24 12:47:31118browse

How Can We Modify Nested Struct Fields Using Reflection to Achieve Persistence?

Using Reflection to Set Nested Struct Fields

Problem:

How can we use reflection to modify the value of a nested struct field in a way that persists?

Code:

<code class="go">type ProductionInfo struct {
    StructA []Entry
}

type Entry struct {
    Field1 string
    Field2 int
}

func SetField(source interface{}, fieldName string, fieldValue string) {
    v := reflect.ValueOf(source)
    tt := reflect.TypeOf(source)

    for k := 0; k < tt.NumField(); k++ {
        fieldValue := reflect.ValueOf(v.Field(k))

        fmt.Println(fieldValue.CanSet())
        if fieldValue.CanSet() {
            fieldValue.SetString(fieldValue.String())
        }
    }
}

func main() {
    source := ProductionInfo{}
    source.StructA = append(source.StructA, Entry{Field1: "A", Field2: 2})

    SetField(source, "Field1", "NEW_VALUE")
}</code>

Issues:

  1. Passing the wrong value: We're attempting to set the field of the top-level ProductionInfo struct, instead of the nested Entry struct. This causes errors because ProductionInfo does not have a Field1 field.
  2. Passing a non-pointer: Reflection cannot modify the fields of non-pointer structs. We need to pass a pointer to the Entry struct.

Solution:

  1. Modify the call to SetField to target the embedded Entry struct:

    <code class="go">SetField(source.StructA[0], "Field1", "NEW_VALUE")</code>
  2. Change the function to accept and modify a pointer to the Entry:

    <code class="go">func SetField(source *Entry, fieldName string, fieldValue string) {
     v := reflect.ValueOf(source).Elem()
    
     fmt.Println(v.FieldByName(fieldName).CanSet())
    
     if v.FieldByName(fieldName).CanSet() {
         v.FieldByName(fieldName).SetString(fieldValue)
     }
    }</code>

Final Code:

<code class="go">package main

import (
    "fmt"
    "reflect"
)

type ProductionInfo struct {
    StructA []Entry
}

type Entry struct {
    Field1 string
    Field2 int
}

func SetField(source *Entry, fieldName string, fieldValue string) {
    v := reflect.ValueOf(source).Elem()

    if v.FieldByName(fieldName).CanSet() {
        v.FieldByName(fieldName).SetString(fieldValue)
    }
}

func main() {
    source := ProductionInfo{}
    source.StructA = append(source.StructA, Entry{Field1: "A", Field2: 2})

    fmt.Println("Before: ", source.StructA[0])
    SetField(&source.StructA[0], "Field1", "NEW_VALUE")
    fmt.Println("After: ", source.StructA[0])
}</code>

Output:

Before:  {A 2}
true
After:  {NEW_VALUE 2}

The above is the detailed content of How Can We Modify Nested Struct Fields Using Reflection to Achieve Persistence?. 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