vendredi 2 février 2018

Now to Set value of a struct with the same definition but different name generated by reflection in golang?

I wrote a function to make a type marshalable, so the main idea is to change all types of keys for maps to string. Here's the function:

type A struct {
    MA map[int]*B
    MB *B
}

type B struct {
    IB int
}

func GetMarshableStruct(src interface{}) interface{} {
    t := reflect.TypeOf(src)
    v := reflect.ValueOf(src)
    kind := t.Kind()
    fmt.Printf("kind %s\n", kind)
    var result reflect.Value
    switch kind {
    case reflect.Map:
        //Find the map layer count
        layer := 0
        cur := t.Elem()
        for reflect.Map == cur.Kind() {
            layer++
            cur = cur.Elem()
        }
        result = reflect.MakeMap(reflect.MapOf(reflect.TypeOf("a"), cur))
        for layer > 0 {
            result = reflect.MakeMap(reflect.MapOf(reflect.TypeOf("a"), result.Type()))
            layer--
        }
        keys := v.MapKeys()
        for _, k := range keys {
            result.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%v", k)), reflect.ValueOf(GetMarshableStruct(v.MapIndex(k).Interface())))
        }
    case reflect.Slice, reflect.Array:
        result = reflect.MakeSlice(t, v.Len(), v.Cap())
        for i := 0; i < v.Len(); i++ {
            result.Index(i).Set(reflect.ValueOf(GetMarshableStruct(v.Index(i).Interface())))
        }
    case reflect.Ptr:
        result = reflect.New(v.Elem().Type())
        result.Elem().Set(reflect.ValueOf(GetMarshableStruct(reflect.Indirect(v).Interface())))
    case reflect.Struct:
        structFields := make([]reflect.StructField, 0)
        fieldValues := make([]reflect.Value, 0)
        for i := 0; i < v.NumField(); i++ {
            tmpV := reflect.ValueOf(GetMarshableStruct(v.Field(i).Interface()))
            fieldValues = append(fieldValues, tmpV)
            sf := reflect.StructField{}
            sf = t.Field(i)
            sf.Type = tmpV.Type()
            structFields = append(structFields, sf)
        }
        resultT := reflect.StructOf(structFields)
        result = reflect.Indirect(reflect.New(resultT))
        for i := 0; i < v.NumField(); i++ {
            fmt.Printf("%s\n", result.Field(i).Type())
            result.Field(i).Set(fieldValues[i])
        }
    default:
        result = v
    }
    return result.Interface()
}

func main() {
    a := new(A)
    a.MA = make(map[int]*B)
    a.MA[4] = new(B)
    a.MA[4].IB = 2
    a.MB = new(B)
    a.MB.IB = 3
    b := GetMarshableStruct(a)
    fmt.Printf("%T %v %T %v\n", a, a, b, b)
}

But I got the error:

panic: reflect.Set: value of type struct { MA map[string]*main.B; MB *main.B } is not assignable to type main.A

goroutine 1 [running]:
panic(0x4c67c0, 0xc42000a550)
        /usr/local/go/src/runtime/panic.go:500 +0x1a1
reflect.Value.assignTo(0xc4200721e0, 0xc42000a540, 0x99, 0x4eb8eb, 0xb, 0x4d4200, 0x0, 0x1, 0xc4200721e0, 0xc42000a540)
        /usr/local/go/src/reflect/value.go:2163 +0x35c
reflect.Value.Set(0x4d4200, 0xc42000a3b0, 0x199, 0xc4200721e0, 0xc42000a540, 0x99)
        /usr/local/go/src/reflect/value.go:1333 +0xa4
main.GetMarshableStruct(0x4c0ca0, 0xc42000a370, 0x4, 0xc42008e048)
        /home/bzhang/devCodeCore/common/src/go/src/audience/scanner/ref.go:149 +0x12e7
main.main()
        /home/bzhang/devCodeCore/common/src/go/src/audience/scanner/ref.go:114 +0x16a
exit status 2

So it seems that when Set() is invoked, the receiver and the parameter must be the same in name? can anyone help with the problem? We can see that the generated struct : struct { MA map[string]*main.B; MB *main.B } is identical to main.A.





Aucun commentaire:

Enregistrer un commentaire