为什么json.Unmarshal返回一个地图而不是预期的结构?

时间:2014-01-30 22:25:55

标签: json go unmarshalling

查看此游乐场:http://play.golang.org/p/dWku6SPqj5

基本上,我正在处理的库接收interface{}作为参数,然后需要json.Unmarshal来自字节数组。在封面下,interface{}参数是一个与字节数组的json结构匹配的结构,但是该库没有对该结构的引用(但它确实引用了相应的reflect.Type通过) 。

为什么json包不能检测基础类型?由于某种原因,它会返回一个简单的地图而不是实际的结构。

以下是代码:

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 个答案:

答案 0 :(得分:3)

您已向json传递指向抽象接口的指针。您只需将指向Ping 的指针作为抽象接口传递:

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?
}

但如果你说你没有指向interface{}的指针,你可以使用reflect来创建一个新的指针,反序列化它,并将值复制回来:

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?
}