0
votes

***see updated field at the bottom,please****

I want to assign a value to a nested struct but it does not work:

try code here

 type MyStruct2 struct {
    Value3 string
}
type myStruct1 struct {
    Value1    string
    Value2    int
    MyStruct2 MyStruct2
}

func main() {
    var ah myStruct1 
    t := reflect.TypeOf(ah)
    where := reflect.ValueOf(&ah).Elem()

    rt0 := t.Field(0)
    field0 := where.FieldByIndex(rt0.Index)
    field0.SetString("hello") 

    rt1 := t.Field(1)
    field1 := where.FieldByIndex(rt1.Index)
    field1.SetInt(4)

    rt2 := t.Field(2)
    rt2_1:=rt2.Type.Field(0)
    field2 := where.FieldByIndex(rt2_1.Index)
    field2.SetString("hello2")//not assigning to struct

    fmt.Printf("%+v\n",ah)
}

output: {Value1:hello2 Value2:4 MyStruct2:{Value3:}}

As you can see, it's not assigning a value to the nested struct

// update:

as @Austin said this is solved by using:

field2 :=where.FieldByIndex(rt2.Index).FieldByIndex(rt2_1.Index)

instead, but it's not working inside function:

try code here

type MyStruct2 struct {
    Value3 string
}
type myStruct1 struct {
    Value1    string
    Value2    string
    MyStruct2 MyStruct2
}

func main() {
    var ah myStruct1
    t := reflect.TypeOf(ah)
    where := reflect.ValueOf(&ah).Elem()
    max := t.NumField()
    for i := 0; i < max; i++ {
        f := t.Field(i)
        findAssing("hello", f, where)
    }
    fmt.Printf("%+v\n", ah)
}

func findAssing(me string, rt reflect.StructField, field reflect.Value) {
    if rt.Type.Kind() == reflect.Struct {
        max := rt.Type.NumField()
        for i := 0; i < max; i++ {
            if rt.Type.Field(i).Type.Kind() == reflect.Struct {
                field = field.FieldByIndex(rt.Type.Field(i).Index)
            }
            findAssing(me, rt.Type.Field(i), field)
        }
    } else {
        field = field.FieldByIndex(rt.Index)
        field.SetString("hello")
    }
}
2

2 Answers

2
votes

You need to select the third field of the outer struct before you select the first field of the inner struct. I.e.,

rt2 := t.Field(2)
rt2_1 := rt2.Type.Field(0)
field2 := where.FieldByIndex(rt2.Index).FieldByIndex(rt2_1.Index)
field2.SetString("hello2") // Will assign to the inner struct now.

Edit: The code in the edited question makes a similar mistake in that it does not fetch the field of the outer struct first. Additionally, it overrides the value of field repeatedly in a way that probably doesn't do what is intended. Something like this should work:

func findAssing(me string, rt reflect.StructField, field reflect.Value) {
    subField := field.FieldByIndex(rt.Index)
    if rt.Type.Kind() == reflect.Struct {
        max := rt.Type.NumField()
        for i := 0; i < max; i++ {
            findAssing(me, rt.Type.Field(i), subField)
        }
    } else {
        subField.SetString("hello")
    }
}
2
votes

If your goal is recursively set all string fields to some value, then use the following code. You don't say what the code is supposed to do, so this is just a guess.

func main() {
    var ah myStruct1
    setStringsInStruct("hello", reflect.ValueOf(&ah).Elem())
    fmt.Printf("%+v\n", ah)
}

func setStringsInStruct(s string, v reflect.Value) {
    t := v.Type()
    for i := 0; i < t.NumField(); i++ {
        sf := t.Field(i)
        switch sf.Type.Kind() {
        case reflect.Struct:
            setStringsInStruct(s, v.Field(i))
        case reflect.String:
            v.Field(i).SetString(s)
        }
    }
}

https://play.golang.org/p/YVjMpk1qMtb