Unmarshal of JSON "null" into a pointer does not make the pointer nil.

486 views
Skip to first unread message

Eddy Reyes

unread,
Jan 21, 2015, 6:03:58 PM1/21/15
to golan...@googlegroups.com
See the following snippet:

http://play.golang.org/p/859PdQMJEl

And here's the code from the snippet:

package main
import (
"encoding/json"
"fmt"
)
type foo struct {
A int
}
func main() {
i := &foo{A: 10}
if err := json.Unmarshal([]byte("null"), i); err != nil {
panic(err)
}
fmt.Println(i)
}

I was expecting that the Unmarshal() would side-effect the value of i such that it equals nil. Instead, the composite literal i points to remains unmodified, and i still points to it. In other words, the Unmarshal had no effect on the state of i.

The docs for json.Unmarshal (http://golang.org/pkg/encoding/json/#Unmarshal) say the following:

The JSON null value unmarshals into an interface, map, pointer, or slice by setting that Go value to nil. Because null is often used in JSON to mean “not present,” unmarshaling a JSON null into any other Go type has no effect on the value and produces no error.

Am I mistaken in believing that the type of i here is a pointer? I modified my snippet to print reflect.TypeOf(i) and it tells me (*main.foo), which seems to me to be a pointer.  You can view that modified snippet here: http://play.golang.org/p/JVJ-C1wNHx

I'm sure I'm likely misunderstanding something... Can someone please explain?

TIA, Eddy

Matthew Kane

unread,
Jan 21, 2015, 6:10:11 PM1/21/15
to Eddy Reyes, golang-nuts
You need another layer of indirection. The type of the value pointed
to by the pointer you pass in must be a pointer. In other words, pass
in &i.
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.



--
matt kane's brain
im: mkb.di...@gmail.com (gtalk) / mkbatwerk (AIM)
twitter: the_real_mkb / nynexrepublic
http://hydrogenproject.com

Eddy Reyes

unread,
Jan 21, 2015, 6:39:10 PM1/21/15
to Matthew Kane, golang-nuts
Thanks Matthew, that does, in fact, make i == nil.

Thinking about how I'd do this in C, this makes sense: To expect some variable to be side-effected, you must pass in a pointer to it so that the consumer can dereference and write into the memory.

In Go, I think the problem is that if you don't add the layer of indirection (passing in &i), the value is not settable according to the 3rd Law of Reflection. In order for the JSON library to side effect the variable, it must do an Elem() of the interface value passed in. For pointers, Elem() follows the reference into the actual value.

Let me know if I misunderstand any of that.

thanks, Eddy
Reply all
Reply to author
Forward
0 new messages