jeudi 13 avril 2017

Updating struct field using reflection

I'm implementing partial update for an entity.

The entity struct looks like

type Entity struct {
    Id string `readonly:"true"`
    Spec     EntitySpec
    Status   EntityState
}


type EntitySpec struct {
    Version *string `readonly:"true"`
    Users    []*User
    Field1   *InnerStruct1
    Field2   []*InnerStruct2
}

and so on.

So I'm trying to use reflection to iterate over Entity struct fields recursively and update fields which user is allowed to update:

func method(existingEntity interface{}, newEntity interface{}) {
    entityType := reflect.TypeOf(existingEntity)
    logger.Debugf("type: %v", entityType)
    for i := 0; i < entityType.NumField(); i++ {
        value := entityType.Field(i)
        logger.Debugf("Name: %s", value.Name)

        tag := value.Tag
        logger.Debugf("tag: %s", tag)
        if tag.Get("readonly") == "true" {
            logger.Debugf("readonly, go to next one")
            continue
        }

        oldField := reflect.Indirect(reflect.ValueOf(existingEntity).Field(i))
        newField := reflect.Indirect(reflect.ValueOf(newEntity).FieldByName(value.Name))
        logger.Debugf("type: %v", value.Type.Kind())
        if value.Type.Kind() == reflect.Struct {
            logger.Debugf("value: %v", oldField)
            //struct, go into it
            method(oldField.Interface(), newField.Interface())
        } else {
            if oldField != newField && oldField.String() != newField.String() {
                logger.Debugf("Type of old field: %v", oldField.Type())
                logger.Debugf("Type of new field: %v", newField.Type())
                logger.Debugf("Update: %v \nTo %v", oldField, newField)
                oldField.Set(newField) //HERE I get the exception
            } else {
                logger.Debugf("Field values are equal")
            }
        }
    }
}

But when I'm trying to assign a new value with oldField.Set(newField), I get an exception:

reflect: reflect.Value.Set using unaddressable value

I've also tried reflect.ValueOf(existingEntity).Field(i).Set(reflect.ValueOf(newEntity).FieldByName(value.Name)) but got the same exception.

Could you explain to me why it happens and how to fix this?





Aucun commentaire:

Enregistrer un commentaire