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

Popular posts from this blog

Spring Boot + JPA + Hibernate: Unable to locate persister -

go - Golang: panic: runtime error: invalid memory address or nil pointer dereference using bufio.Scanner -

c - double free or corruption (fasttop) -