json - Golang interface{} type misunderstanding -
i got bug in go when using interface{} function parameter type, when given non-pointer type, , using json.unmarshal it.
because piece of code worth thousand words, here example:
package main import ( "encoding/json" "fmt" ) func test(i interface{}) { j := []byte(`{ "foo": "bar" }`) fmt.printf("%t\n", i) fmt.printf("%t\n", &i) json.unmarshal(j, &i) fmt.printf("%t\n", i) } type test struct { foo string } func main() { test(test{}) } which outputs:
main.test *interface {} map[string]interface {} json.unmarshal turns struct map[string]interface{} oo...
little readings later explains of it, interface{} type in itself, not sort of typeless container, explains *interface{}, , fact json.unmarshal not initial type, , returned map[string]interface{}..
from unmarshal docs:
to unmarshal json interface value, unmarshal stores 1 of these in interface value: [...]
and if pass pointer test function so, works:
func test(i interface{}) { j := []byte(`{ "foo": "bar" }`) fmt.printf("%t\n", i) fmt.printf("%t\n", &i) json.unmarshal(j, i) fmt.printf("%t\n", i) fmt.println(i) } func main() { test(&test{}) } which outputs:
*main.test *interface {} *main.test &{bar} cool, data unmarshalled , all, in second snippet removed & when calling unmarshal. because have *test in i, no use it.
so in logic, if put & i when calling unmarshal should mess i's type again. no.
if run:
func test(i interface{}) { j := []byte(`{ "foo": "bar" }`) fmt.printf("%t\n", i) fmt.printf("%t\n", &i) json.unmarshal(j, &i) fmt.printf("%t\n", i) fmt.println(i) } func main() { test(&test{}) } well still works:
*main.test *interface {} *main.test &{bar} and i'm out of google search queries.
the right scenario
interface{} wrapper value , of type. interface schematically wraps (value; type) pair, concrete value , type. more details on this: the laws of reflection #the representation of interface.
json.unmarshal() takes value of type interface{}:
func unmarshal(data []byte, v interface{}) error so if have interface{} value (the i interface{} parameter of test() function), don't try take address, pass along as-is.
also note package modify value stored in interface{}, need pass pointer it. should in i pointer. right scenario pass *test test(), , inside test() pass i json.unmarshal() (without taking address).
explanation of other scenarios
when i contains *test , pass &i, work because json package dereference *interface{} pointer, , finds interface{} value, wraps *test value. it's pointer, it's good: unmarshals json object pointed test value.
when i contains test , pass &i, same thing goes above: *interface{} dereferenced, finds interface{} contains non-pointer: test. since json package can't unmarshal non-pointer value, has create new value. , since passed value json.unmarshal() function of type *interface{}, tells json package unmarshal data value of type interface{}. means json package free choose type use. , default json package unmarshals json objects map[string]interface{} values, what's created , used (and put value pointed pointer passed: &i).
all in all
all in all, avoid using pointers interfaces. instead "put" pointers interfaces (the interface value should wrap pointer). when have interface{} holding pointer, pass along.
Comments
Post a Comment