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
Labels
Documentation FrozenDueToAge NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Milestone

Comments

@ghost
Copy link

ghost 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
Copy link
Contributor

cespare 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 Documentation NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. labels Jul 13, 2017
@bradfitz bradfitz added this to the Go1.10 milestone Jul 13, 2017
@ghost
Copy link
Author

ghost 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
Copy link
Contributor

rsc 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 as completed 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.
Labels
Documentation FrozenDueToAge NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Projects
None yet
Development

No branches or pull requests

4 participants