英文:
Convert interface{} from JSON to one of multiple concrete types
问题
我一直在寻找解决这个问题的方法,在这里没有找到。我不确定是否可能,但还是值得问一下。
我有一个接口,我的应用程序从服务器读取JSON数据。可能会返回几种类型,所以我使用interface{}
来消费它。
在将JSON字节解组为interface{}
之后,我如何将其转换为具体类型?如果失败,我希望检查下一个类型进行转换,直到成功转换为止。
大致代码如下(为了简洁起见,删除了一些代码):
type Fooer interface {
Foo()
}
type A struct { }
func (a *A) Foo() { .. }
type B struct { }
func (b *B) Foo() { .. }
// resp is io.ReadCloser
func heavvyWork(resp) {
var parsedResp interface{}
bytesData, err := ioutil.ReadAll(resp)
json.Unmarshal(bytesData, parsedResp)
// 将parsedResp转换为具体类型,可能是A或B结构体
// 尝试A,如果失败,则尝试B。
...
concreteType.Foo()
}
我已经查看了类型断言和类型转换,但无法使其工作。
在Go中是否可能实现这个功能?
JSON响应内容的示例:
A:
{
"data": {
"access_key": "AKIA...",
"secret_key": "xlCs...",
}
}
B:
{
"data": {
"data": {
"foo": "bar"
},
"metadata": {
...
}
}
}
英文:
I've been looking around for a solution to this problem, and couldn't find one here on SO. I'm not sure it's possible, but its worth asking.
I have an interface, and my app reads JSON data from a server. There are few types that might return in response, so I'm using interface{}
to consume it.
After I've unmarshaled the json bytes to an interface{}
, how can I convert it to a concrete type? If it fails, I would like to check the next type for conversation, until I have a successful conversation.
It looks something like this (some code is removed for brevity)
type Fooer interface {
Foo()
}
type A struct { }
func (a *A) Foo() { .. }
type B struct { }
func (b *B) Foo() { .. }
// resp is io.ReadCloser
func heavvyWork(resp) {
var parsedResp interface{}
bytesData, err := ioutil.ReadAll(resp)
json.Unmarshal(bytesData, parsedResp)
// convert parsedResp to a concrete type, it might be A or B struct
// try A, if fails, try B.
...
concreteType.Foo()
}
I have looked over type assertions and casting, but couldn't get this to work.
Is that possible with Go?
Example for JSON response content
A:
{
"data": {
"access_key": "AKIA...",
"secret_key": "xlCs...",
}
}
B:
{
"data": {
"data": {
"foo": "bar"
},
"metadata": {
...
}
}
}
答案1
得分: 1
你有几个选择,但没有一个是完全理想的。
首先,你可以直接在地图中查找键。我在这里写了一个示例,点击这里。这个示例旨在提供指导,但并不特别高效或其他方面。
其次,你可以使用json.RawMessage
来延迟解析。我在这里写了一个示例,点击这里。请注意,我在解码器中使用了各种结构体的指针成员。这会让事情变得麻烦:你可能希望在解码时使用指针化的数据类型,并在选择了类型后使用非指针类型。但这样做可以让你直接使用更多的json包功能(通过结构体标签)。
另一种方法是使用json.NewDecoder
获取流解码器并进行处理。这可能是最健壮的方法,但也是最棘手的方法。
英文:
You have options. None of them are exactly wonderful.
One is, as mentioned, to just look inside the map for keys. I wrote up an example of this here. It's meant to be instructive, but not particularly efficient or anything.
Another is to use json.RawMessage
to defer parsing a bit. I wrote up an example of this here. Note how I resort to pointer members of the various struct
s in the decoder. This makes things annoying: you might want to have pointer-ized data types just for the decode, and use non-pointer types once you've picked a type. But it does let you use more of the json package directly (via struct tags).
Yet another is to use json.NewDecoder
to get a stream decoder and work through it. This would probably be the most robust method, but also the trickiest.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论