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

为什么json.Unmarshal返回一个映射而不是预期的结构?,json,go,unmarshalling,Json,Go,Unmarshalling,看看这个操场: 基本上,我正在处理的库接收一个接口{}作为参数,然后需要json.Unmarshal将其从字节数组中取出。在封面下,interface{}参数是一个与字节数组的json结构匹配的结构,但是库没有对该结构的引用(但是它有对相应reflect.Type-through的引用) 为什么json包不能检测底层类型?出于某种原因,它会返回一个简单的映射,而不是实际的结构 代码如下: package main import "fmt" import "encoding/json" impo

看看这个操场:

基本上,我正在处理的库接收一个
接口{}
作为参数,然后需要
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"`
}

您已经向
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?
}

那行得通,但我做不到。该库不知道大型应用程序使用的底层类型。“ping”作为
接口{}
接收,就是这样。有什么想法吗?你可以用
reflect
告诉
interface{}
的底层类型,并创建一个新的
interface{}
来表示指向它的指针。我很乐意看到这一点——是否愿意修改游乐场示例并发布修改?如果你不介意创建一个新的ping实例的话(我不确定这里的假设是什么),这很简单。但我有一种预感,它不会削减它:@不是高尔夫球手-那个运动场可能正好可以完成这项工作,因为图书馆实际上可以访问reflect.TypeOf(Ping),所以我们称之为reflect.New(…)。谢谢!我将编辑我的问题,以表明库没有对结构本身的引用,但它可能有reflect.Type。如果您将答案编辑为包含reflect.New内容,我将接受它。
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?
}