具有更高类型断言的json.Unmarshal接口指针

具有更高类型断言的json.Unmarshal接口指针,json,go,unmarshalling,Json,Go,Unmarshalling,因为我经常解组http.Response.Body,所以我想我可以编写一个函数来处理读取、关闭和解组到各种不同结构中的所有麻烦。这就是为什么我引入了一个函数func unmarhalInterface(closer*io.ReadCloser,v*interface{})error,然后可以用t:=I.(t)断言返回值 据我所知,我已经将它包装成一个类型为*interface{}的值,但是由于上面的类型是interface{},而不是myStruct,因此json包实现选择map[string]

因为我经常解组http.Response.Body,所以我想我可以编写一个函数来处理读取、关闭和解组到各种不同结构中的所有麻烦。这就是为什么我引入了一个函数
func unmarhalInterface(closer*io.ReadCloser,v*interface{})error
,然后可以用
t:=I.(t)
断言返回值

据我所知,我已经将它包装成一个类型为
*interface{}
的值,但是由于上面的类型是
interface{}
,而不是
myStruct
,因此
json
包实现选择
map[string]interface{}
。之后,类型断言失败(当然)。我是否缺少任何东西或需要此实现“手动”类型断言,这意味着查找映射中的所有字段,并将这些字段分配到我的结构中

下面的代码具有注释中带有符号的最小示例。如果我的解释不充分,请马上问

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "io/ioutil"
    "log"
)

type myStruct struct {
    A string `json:"a"`
    B string `json:"b"`
}

func main() {
    jsonBlob := []byte(`{"a":"test","b":"test2"}`)

    var foo = interface{}(myStruct{})
    closer := ioutil.NopCloser(bytes.NewReader(jsonBlob))

    err := unmarshalCloser(&closer, &foo)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(fmt.Sprintf("%v", foo))

    // That´s what i want:
    foo2 := foo.(myStruct)
    fmt.Println(foo2.A)
}

func unmarshalCloser(closer *io.ReadCloser, v *interface{}) error {
    defer func() { _ = (*closer).Close() }()

    data, err := ioutil.ReadAll(*closer)
    if err != nil {
        return err
    }

    err = json.Unmarshal(data, v)
    if err != nil {
        return err
    }
    return nil
}


空接口不是实际的类型,它基本上是与任何东西都匹配的东西。如注释中所述,指向空接口的指针实际上没有意义,因为指针已经匹配空接口,因为所有内容都匹配空接口。为了使代码正常工作,您应该删除结构周围的接口包装器,因为这会搞乱json类型检查,而空接口的关键是您可以向它传递任何内容


链接的答案是不要使用
*接口{}
。唯一需要指向接口的指针的时间是,如果要将空接口传递给
Unmarshal
本身。另外,为什么还将
*io.ReadCloser
作为参数?几乎没有理由传递指向接口的指针(如果你想通过反射分配给接口,上面的例外就是少数例外)@j我也尝试过不使用指针,但同样的问题仍然存在。同样的接口转换问题,即使json.unmarshal现在获得正确的类型作为输入。试过什么?如果删除所有接口指针,它将按预期工作:。这与您试图实现的有什么不同?空接口肯定是一种类型:。
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "io/ioutil"
    "log"
)

type myStruct struct {
    A string `json:"a"`
    B string `json:"b"`
}

func main() {
    jsonBlob := []byte(`{"a":"test","b":"test2"}`)

    var foo = &myStruct{} // This need to be a pointer so its attributes can be assigned
    closer := ioutil.NopCloser(bytes.NewReader(jsonBlob))

    err := unmarshalCloser(closer, foo)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(fmt.Sprintf("%v", foo))

    // That´s what i want:
    fmt.Println(foo.A)
}

// You don't need to declare either of these arguments as pointers since they're both interfaces
func unmarshalCloser(closer io.ReadCloser, v interface{}) error {
    defer closer.Close()
    // v NEEDS to be a pointer or the json stuff will barf

    // Simplified with the decoder
    return json.NewDecoder(closer).Decode(v)
}