问题
See this playground: http://play.golang.org/p/dWku6SPqj5
Basically, the library I'm working on receives an interface{}
as a parameter and then needs to json.Unmarshal
that from a byte array. Under the covers, the interface{}
parameter is a struct that matches the json structure of the byte array but the library doesn't have a reference to that struct (but it does have a reference to the corresponding reflect.Type through).
Why can't the json package detect the underlying type? For some reason it's giving back a simple map instead of the actual struct.
Here's the code:
package main
import "fmt"
import "encoding/json"
import "reflect"
func main() {
good()
bad()
}
func good() {
var ping Ping = Ping{}
deserialize([]byte(`{"id":42}`), &ping)
fmt.Println("DONE:", ping.ID)
}
func bad() {
var ping interface{} = Ping{}
deserialize([]byte(`{"id":42}`), &ping)
fmt.Println("DONE:", ping) // It's a simple map now, not a Ping. Why?
}
func deserialize(stuff []byte, thing interface{}) {
value := reflect.ValueOf(thing)
fmt.Printf("%+v | %v\n", value, value.Kind())
err := json.Unmarshal(stuff, thing)
if err != nil {
panic(err)
}
}
type Ping struct {
ID int `json:"id"`
}
回答1:
You've passed to json
a pointer to an abstract interface. You should simply pass a pointer to Ping
as an abstract interface:
func bad() {
var ping interface{} = &Ping{} // <<<< this
deserialize([]byte(`{"id":42}`), ping) // << and this
fmt.Println("DONE:", ping) // It's a simple map now, not a Ping. Why?
}
But if as you said you don't have a pointer to cast ton an interface{}
, you can use reflect to create a new pointer, deserialize into it, and copy the value back:
func bad() {
var ping interface{} = Ping{}
nptr := reflect.New(reflect.TypeOf(ping))
deserialize([]byte(`{"id":42}`), nptr.Interface())
ping = nptr.Interface()
fmt.Println("DONE:", ping) // It's a simple map now, not a Ping. Why?
}
来源:https://stackoverflow.com/questions/21468741/why-does-json-unmarshal-return-a-map-instead-of-the-expected-struct