如何在Go中将JSON解组为接口

huangapple go评论87阅读模式
英文:

How to Unmarshal JSON into an interface in Go

问题

我正在尝试同时从多个不同的JSON响应中解组和剥离字段,并将其放入适当的Go结构体中。为此,我创建了一个Wrappable接口,定义了Unwrap方法(用于剥离相应的字段),并将该接口传递给解组和剥离代码。以下是一个示例(也可以在http://play.golang.org/p/fUGveHwiz9上找到):

package main

import (
    "encoding/json"
    "fmt"
)

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

type DataWrapper struct {
    Elements []Data `json:"elems"`
}

type Wrapper interface {
    Unwrap() []interface{}
}

func (dw DataWrapper) Unwrap() []interface{} {
    result := make([]interface{}, len(dw.Elements))
    for i := range dw.Elements {
        result[i] = dw.Elements[i]
    }
    return result
}

func unmarshalAndUnwrap(data []byte, wrapper Wrapper) []interface{} {
    err := json.Unmarshal(data, &wrapper)
    if err != nil {
        panic(err)
    }
    return wrapper.Unwrap()
}

func main() {
    data := `{"elems": [{"a": "data", "b": "data"}, {"a": "data", "b": "data"}]}`
    res := unmarshalAndUnwrap([]byte(data), DataWrapper{})
    fmt.Println(res)
}

然而,当我运行代码时,Go会抛出以下错误:

panic: json: cannot unmarshal object into Go value of type main.Wrapper

看起来解组器不希望接收一个指向接口的指针。鉴于我可以使用reflect包在unmarshalAndUnwrap方法中访问底层类型和字段,我对此感到有些惊讶。有人可以解释一下这个问题,并提供如何解决它的见解吗?

英文:

I am trying to simultaneously unmarshal and strip fields from a number of different JSON responses into appropriate Go structs. To do this, I created a Wrappable interface that defines the Unwrap method (which strips the appropriate fields) and pass that interface to the code that unmarshals and unwraps. It looks like the following example (also at http://play.golang.org/p/fUGveHwiz9):

package main

import (
    "encoding/json"
    "fmt"
)

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

type DataWrapper struct {
    Elements []Data `json:"elems"`
}

type Wrapper interface {
    Unwrap() []interface{}
}

func (dw DataWrapper) Unwrap() []interface{} {
    result := make([]interface{}, len(dw.Elements))
    for i := range dw.Elements {
        result[i] = dw.Elements[i]
    }
    return result
}

func unmarshalAndUnwrap(data []byte, wrapper Wrapper) []interface{} {
    err := json.Unmarshal(data, &wrapper)
    if err != nil {
        panic(err)
    }
    return wrapper.Unwrap()
}

func main() {
    data := `{"elems": [{"a": "data", "b": "data"}, {"a": "data", "b": "data"}]}`
    res := unmarshalAndUnwrap([]byte(data), DataWrapper{})
    fmt.Println(res)
}

However, when I run the code, Go panics with the following error:

panic: json: cannot unmarshal object into Go value of type main.Wrapper

It seems the unmarshaller doesn't want to be passed a pointer to an interface. I am somewhat surprised by this given that I can get at the underlying type and fields using the reflect package within the unmarshalAndUnwrap method. Can anyone provide insight into this problem and how I might work around it?

答案1

得分: 2

正如你所说,传递一个非指针会失败。你为什么要这样做呢?

res := unmarshalAndUnwrap([]byte(data), DataWrapper{})

替换为

res := unmarshalAndUnwrap([]byte(data), &DataWrapper{})

这样应该可以解决问题,并且避免不必要的拷贝。

这个错误应该能帮助你理解:http://play.golang.org/p/jXxCxPQDOw

英文:

As you stated, passing a non-pointer fails. Why are you trying to do this anyway?

Replace

res := unmarshalAndUnwrap([]byte(data), DataWrapper{})

by

res := unmarshalAndUnwrap([]byte(data), &DataWrapper{})

It should do the trick and it avoid unnecessary copy.

This error should help you understand: http://play.golang.org/p/jXxCxPQDOw

huangapple
  • 本文由 发表于 2013年7月23日 03:59:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/17796333.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定