我正在使用以这种方式格式化其响应的API:
{
"err": 0,
"data": **Other json structure**
}
我现在得到回复的方式是我将响应放在这样的结构中:
type Response struct {
Err int `json:"err"`
Data interface{} `json:"data"`
}
然后我在收到回复后这样做
jsonbytes, _ := json.Marshal(resp.Data)
json.Unmarshal(jsonBytes, &dataStruct)
我只是忽略了这个例子的错误 当我知道数据应该是什么样子以及它应该是什么类型时,我正在编组和解组似乎有点奇怪。
是否有更简单的解决方案,我没有看到或这是正常的事情?
编辑:我应该提一下,响应对象中的Data属性可能会有所不同,具体取决于我正在做的API调用。
答案 0 :(得分:2)
JSON unmarshaller使用反射来查看它解组的类型。如果未经初始化interface{}
作为解组数据的目标,则会将JSON object
解组为map[string]interface{}
(example in playground)。
以下是一些想法。
如果您知道数据类型,则可以为每种类型定义新的响应结构。例如:
type FooResponse struct {
Err int `json:"err"`
Data Foo `json:"data"`
}
type Foo struct {
FooField string `json:"foofield"`
}
type BarResponse struct {
Err int `json:"err"`
Data Bar `json:"data"`
}
type Bar struct {
BarField string `json:"barfield"`
}
如果您希望每个类型只有一个Response
结构而不是一个结构,那么您可以告诉JSON unmarshaller避免在以后使用data
解组json.RawMessage
字段。数据类型:
package main
import (
"encoding/json"
"fmt"
"log"
)
type Response struct {
Err int `json:"err"`
Data json.RawMessage `json:"data"`
}
type Foo struct {
FooField string `json:"foofield"`
}
type Bar struct {
BarField string `json:"barfield"`
}
func main() {
fooRespJSON := []byte(`{"data":{"foofield":"foo value"}}`)
barRespJSON := []byte(`{"data":{"barfield":"bar value"}}`)
var (
resp Response
foo Foo
bar Bar
)
// Foo
if err := json.Unmarshal(fooRespJSON, &resp); err != nil {
log.Fatal(err)
}
if err := json.Unmarshal(resp.Data, &foo); err != nil {
log.Fatal(err)
}
fmt.Println("foo:", foo)
// Bar
if err := json.Unmarshal(barRespJSON, &resp); err != nil {
log.Fatal(err)
}
if err := json.Unmarshal(resp.Data, &bar); err != nil {
log.Fatal(err)
}
fmt.Println("bar:", bar)
}
输出:
foo: {foo value}
bar: {bar value}
https://play.golang.org/p/Y7D4uhaC4a8
@mkopriva在对该问题的评论中指出的第三个选项是使用interface{}
作为中间数据类型并将其初始化为已知数据类型。
重点在于中介这个词 - 当然最好避免传递interface{}
(Rob Pike's Go Proverbs)。这里的用例是允许使用任何数据类型,而不需要多个不同的Response
类型。在避免暴露interface{}
的方法是完全包装响应,只暴露数据和错误:
package main
import (
"encoding/json"
"fmt"
"log"
)
type Foo struct {
FooField string `json:"foofield"`
}
type Bar struct {
BarField string `json:"barfield"`
}
type Error struct {
Code int
}
func (e *Error) Error() string {
return fmt.Sprintf("error code %d", e.Code)
}
func unmarshalResponse(data []byte, v interface{}) error {
resp := struct {
Err int `json:"err"`
Data interface{} `json:"data"`
}{Data: v}
if err := json.Unmarshal(data, &resp); err != nil {
return err
}
if resp.Err != 0 {
return &Error{Code: resp.Err}
}
return nil
}
func main() {
fooRespJSON := []byte(`{"data":{"foofield":"foo value"}}`)
barRespJSON := []byte(`{"data":{"barfield":"bar value"}}`)
errRespJSON := []byte(`{"err": 123}`)
// Foo
var foo Foo
if err := unmarshalResponse(fooRespJSON, &foo); err != nil {
log.Fatal(err)
}
fmt.Println("foo:", foo)
// Bar
var bar Bar
if err := unmarshalResponse(barRespJSON, &bar); err != nil {
log.Fatal(err)
}
fmt.Println("bar:", bar)
// Error response
var v interface{}
if err := unmarshalResponse(errRespJSON, &v); err != nil {
log.Fatal(err)
}
}
输出:
foo: {foo value}
bar: {bar value}
2009/11/10 23:00:00 error code 123