nested non-addressable values cannot be merged
My specific problem is this: given two structs with interface{} fields that contain struct values of the same type, the interface{} fields are not deeply merged.
type testStruct struct {
Name string
Value string
}
type interfaceStruct struct {
Field interface{}
}
dst := interfaceStruct{
Field: &testStruct{
Value: "keepMe",
},
}
src := interfaceStruct{
Field: &testStruct{
Name: "newName",
},
}
mergo.Merge(&dst, src)
expected value of dst:
{
Field: {
Name: "newName",
Value: "keepMe",
},
}
actual value of dst:
{
Field: {
Name: "",
Value: "keepMe",
},
}
The reason for this is that merge.go:267 calls deepMerge with the interface values ([value].Elem()
). However, since those are values in a field of type interface{}, they're not addressable (did not expect that, learned something today). The recursive call will end up in the default case of that switch statement, and on line merge.go:275, CanSet() will be false (because CanAddr() is false), and you'll try assigning dst = src
.
But there's a problem with that. dst is of type reflect.Value, which is not merely a Value, it's a value. It's not a pointer. That assignment can't modify any memory outside of that method. As soon as the argument for deepMerge, dst, stops being addressable, deepMerge can no longer modify dst, which is its implicit return value. It may as well return immediately.
deepMerge used to return (dst reflect.Value, err error)
. It was changed recently, and I'm not sure why. The change, unfortunately, prevents me from deeply merging equal values in interfaces, as appears to be the intent of merge.go:266-271. Would you be open to going back to returning (dst, err) so that dst can be set back up at the interface level where it's still addressable? If you are ok with that change, I'm happy to make a pull request for it!
All files and line numbers as of v0.3.11
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too