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