"To unmarshal a JSON array into a slice, Unmarshal resets the slice length 
to zero and then appends each element to the slice."

And you gave "&newElems" to Unmarshal twice. So it zeroed the length, and 
appended the second time,
effectively overwriting the first (and only) element.
This is intended behaviour.

The problem is not this, but your use of newElems - although it's length is 
zeroed, the first element is still there, so Unmarshal uses it, and fills P,
instead of allocating a new *int.

If you zero out the element, it will allocate a new pointer, as you want:

https://go.dev/play/p/vgkbG0LZ2nr

Mateusz Wójcik a következőt írta (2022. augusztus 23., kedd, 1:01:01 UTC+2):

> The test code below demonstrates a json.Unmarshal behavior that I find 
> unexpected. The code unmarshals arrays of objects with pointers fields. All 
> unmarshaled objects end up sharing the same pointer value, effectively 
> overwriting the contents of the pointer.
>
> package unmarshall
>
> import (
>     "encoding/json"
>     "fmt"
>     "testing"
>
>     "github.com/stretchr/testify/assert"
> )
>
> func TestUnmarshal(t *testing.T) {
>     type Elem struct {
>         V int
>         P *int
>     }
>
>     elems := []Elem(nil)
>     newElems := []Elem(nil)
>
>     json.Unmarshal([]byte(`[{"V":10, "P":1}]`), &newElems)
>     elems = append(elems, newElems...)
>
>     json.Unmarshal([]byte(`[{"V":20, "P":2}]`), &newElems)
>     elems = append(elems, newElems...)
>
>     assert.Equal(t, 10, elems[0].V)
>     assert.Equal(t, 1, *elems[0].P)
>
>     assert.Equal(t, 20, elems[1].V)
>     assert.Equal(t, 2, *elems[1].P)
>
>     assert.NotEqual(t, elems[0].P, elems[1].P)
> }
>
> ​
> I find the behavior unexpected because the documentation of json.Unmarshal 
> states:
>
> // To unmarshal a JSON array into a slice, Unmarshal resets the slice length
> // to zero and then appends each element to the slice.
>
> ​
> However, reseting the slice length to zero and appending elements to the 
> slice results in different behavior:
>
> func TestAppend(t *testing.T) {
>    type Elem struct {
>       V int
>       P *int
>    }
>
>    elems := []Elem(nil)
>    newElems := []Elem(nil)
>
>    one, two := 1, 2
>
>    newElems = append(newElems[:0], Elem{V: 10, P: &one})
>    elems = append(elems, newElems...)
>
>    newElems = append(newElems[:0], Elem{V: 20, P: &two})
>    elems = append(elems, newElems...)
>
>    assert.Equal(t, 10, elems[0].V)
>    assert.Equal(t, 1, *elems[0].P)
>
>    assert.Equal(t, 20, elems[1].V)
>    assert.Equal(t, 2, *elems[1].P)
>
>    assert.NotEqual(t, elems[0].P, elems[1].P)
> }
>
> ​
> Are my expectations of the above behavior incorrect?
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/a7613b82-a134-445e-94b3-3cd48471f576n%40googlegroups.com.

Reply via email to