一尘不染

为什么json.Unmarshal返回映射而不是预期的结构?

go

看到这个游乐场:http :
//play.golang.org/p/dWku6SPqj5

基本上,我正在使用的库interface{}将a作为参数接收,然后需要json.Unmarshal从字节数组中获取。在幕后,该interface{}参数是一个与字节数组的json结构匹配的结构,但该库没有对该结构的引用(但它确实具有对相应的reflect.Type
through的引用)。

为什么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"`
}

阅读 212

收藏
2020-07-02

共1个答案

一尘不染

您已经传递了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?
}

但是,如您所说,如果您没有指针可以转换为an 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?
}
2020-07-02