deepcopy
deepcopy copied to clipboard
There are cases we cannot deepcopy
Hello!
Somehow Copy function cannot deepcopy an array of list of list. A example test is following.
package deepcopytest
import (
"testing"
"github.com/mohae/deepcopy"
)
type a [3][][]float64
var source = a{
{
{
1.0,
2.0,
3.0,
},
},
}
func TestDeepcopy(t *testing.T) {
distination := deepcopy.Copy(source).(a)
source[0][0][0] = 4.0
source[0][0][1] = 5.0
source[0][0][2] = 6.0
if distination[0][0][0] == source[0][0][0] {
t.Fatal("Isn't deepcopied!", distination, source)
}
}
Please make it can deepcopy. Thank you.
Here is a live demo on the Go playground with a simplified test case: type [1][]int.
` case reflect.Array: nv := reflect.New(original.Type()) arrCopyValue := nv.Elem() num := original.Len()
for i := 0; i < num; i++ {
itemValue := original.Index(i)
copyValue := reflect.New(itemValue.Type()).Elem()
copyRecursive(original.Index(i), copyValue)
arrCopyValue.Index(i).Set(copyValue)
}
cpy.Set(arrCopyValue)
`
The author treats the array behavior wrongly, which relies on its deep copy entirely. Any reference type array will be affected by this case. Here are more test cases. @HarutakaMatsumoto I will try to create a fix recently.
func TestArrayOfSomething(t *testing.T) {
verifyCases := map[string]struct {
modifyAndVerify func(t *testing.T)
}{
// failed because the map(underlying is a pointer) will be copied directly
"array of map": {
modifyAndVerify: func(t *testing.T) {
origin := [1]map[string]int{
{
"1": 1,
},
}
copied := deepcopy.Copy(&origin)
assert.NotSame(t, origin, copied)
assert.NotSame(t, origin[0], copied.(*[1]map[string]int)[0])
origin[0]["1"] = 999
assert.Equal(t, 1, copied.(*[1]map[string]int)[0]["1"])
},
},
// failed because the pointer of map will be copied directly
"array of *map": {
modifyAndVerify: func(t *testing.T) {
origin := [1]*map[string]int{
{
"1": 1,
},
}
copied := deepcopy.Copy(&origin)
assert.NotSame(t, origin, copied)
assert.NotSame(t, origin[0], copied.(*[1]*map[string]int)[0])
(*origin[0])["1"] = 999
assert.Equal(t, 1, (*copied.(*[1]*map[string]int)[0])["1"])
},
},
// failed because the pointer of int will be copied directly
"array of *int": {
modifyAndVerify: func(t *testing.T) {
intp := func(i int) *int {
return &i
}
arrayOfInt := [3]*int{intp(1), intp(2)}
copied := deepcopy.Copy(&arrayOfInt)
assert.NotSame(t, &arrayOfInt, copied)
assert.NotSame(t, arrayOfInt[0], copied.(*[3]*int)[0])
arrayOfInt[0] = intp(999)
assert.Equal(t, 1, *copied.(*[3]*int)[0])
},
},
// succeed because int will be copied by value
"array of int": {
modifyAndVerify: func(t *testing.T) {
arrayOfInt := [3]int{1, 2}
copied := deepcopy.Copy(&arrayOfInt)
assert.NotSame(t, &arrayOfInt, copied)
assert.NotSame(t, &arrayOfInt[0], copied.(*[3]int)[0])
arrayOfInt[0] = 999
assert.Equal(t, 1, copied.(*[3]int)[0])
},
},
}
for key, tt := range verifyCases {
t.Run(key, tt.modifyAndVerify)
}
}
Hello @xieyuschen . Oh! Thank you for your fixing! I try to use it.