Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

encoding/json: Unmarshal replaces interface{} types instead of acting on the underlying type #20994

Closed
ghost opened this issue Jul 13, 2017 · 3 comments

Comments

Projects
None yet
4 participants
@ghost
Copy link

commented Jul 13, 2017

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version go1.8.3 darwin/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"

What did you do?

Unmarshal to existing map[string]interface{} that is hidden behind an interface{}:
https://play.golang.org/p/kgaRznDOwb

var test interface{}
if err := json.Unmarshal([]byte(`{"A": "B"}`), &test); err != nil {
	panic(err)
}
fmt.Printf("First:\n %+v\n", test)

if err := json.Unmarshal([]byte(`{"C": "D"}`), &test); err != nil {
	panic(err)
}
fmt.Printf("Second:\n %+v\n", test)

What did you expect to see?

First:
map[A:B]
Second:
map[A:B C:D]

According to docs:

To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:
...
map[string]interface{}, for JSON objects

To unmarshal a JSON object into a map, Unmarshal first establishes a map to use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal reuses the existing map, keeping existing entries.

I expect unmarshal to reuse the existing map, instead of replacing it.

What did you see instead?

First:
map[A:B]
Second:
map[C:D]

@cespare

This comment has been minimized.

Copy link
Contributor

commented Jul 13, 2017

The target value is an interface, not a map (even though the concrete type happens to be a map for the second call). Therefore only the first bit of documentation you quoted applies, not the second.

I think the behavior is as intended, but the documentation could be a bit more explicit.

@bradfitz bradfitz added this to the Go1.10 milestone Jul 13, 2017

@ghost

This comment has been minimized.

Copy link
Author

commented Jul 13, 2017

I was confused about first establishes a map to use and thought that it actually reuses the existing map, because it is not nil. I do see from the source code that this behavior is intentional.

@rsc

This comment has been minimized.

Copy link
Contributor

commented Nov 22, 2017

The behavior is intended and I think pretty explicit. The text says "Unmarshal stores one of these in the interface value:" and so it does. I don't think there's more to say here that's useful.

@rsc rsc closed this Nov 22, 2017

@golang golang locked and limited conversation to collaborators Nov 22, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.