我正在通过编写一个简单的http服务器来学习Go,我需要处理一些JSON响应。
通过对象响应,我可以用2行代码解释它: structResult:= Foo {} json.Unmarshal(structBody,& structResult)
我不知道如何对数组响应做同样的事情(参见下面的例子)。有没有办法指定(可能通过json标签)顶级数组应该进入给定的struct字段?
package main
import "fmt"
import "encoding/json"
type Foo struct {
Id uint64 `json:"id"`
Name string `json:"name"`
}
type BaseResult struct {
Error string `json:"error"`
}
type FooResult struct {
BaseResult
Foos []Foo
}
func main() {
// Simple and works.
structBody := []byte(`{"id": 1,"name": "foo"}`)
structResult := Foo{}
json.Unmarshal(structBody, &structResult)
fmt.Printf("%#v\n", structResult)
// Doesn't work.
arrayBody := []byte(`[{"id": 1,"name": "foo"},{"id": 2,"name": "bar"},{"id": 3,"name": "foobar"}]`)
arrayResult := FooResult{}
json.Unmarshal(arrayBody, &arrayResult)
fmt.Printf("%#v\n", arrayResult)
}
我知道我可以让FooResult成为一个数组:
type FooResult []Foo
然后我失去了指定基础对象的能力,我想用它来存储错误信息等。我也知道我可以直接解组到& fooResult.Foos,但我希望代码可以同时使用对象和数组。
更新
按照@dyoo的建议实现UnmarshalJSON部分解决了我的问题,但是我希望在JSON具有不同结构的情况下我可以使用BaseResult来存储解析错误:
arrayBody := []byte(`{"error": "foo"}`)
arrayResult := FooResult{}
json.Unmarshal(arrayBody, &arrayResult)
fmt.Printf("%#v\n", arrayResult)
当然我可以在UnmarshalJSON中实现更复杂的逻辑 - 但是有没有更简单的方法呢?
答案 0 :(得分:1)
您可以在FooResult
中实施json.Unmarshaler
界面,以准确定制它对解组的响应方式。 (同样,还有一个json.Marshaler
界面。)
添加:
func (f *FooResult) UnmarshalJSON(bs []byte) error {
return json.Unmarshal(bs, &f.Foos)
}
之后你的代码应该工作。 http://play.golang.org/p/oMdoB2e-rB
您可以尝试以下方式:
func (f *FooResult) UnmarshalJSON(bs []byte) error {
err1 := json.Unmarshal(bs, &f.BaseResult)
err2 := json.Unmarshal(bs, &f.Foos)
if err1 != nil && err2 != nil {
// Arbitrarily choose an error.
return err1
}
return nil
}
尽管即使这开始看起来很可疑。处理联合类型结果并不是json库设计为您自动处理的结果。如果您的JSON具有动态类型,则需要显式编写强制逻辑。
有关相关问题,请参阅:How to unmarshall an array of different types correctly?和http://blog.golang.org/json-and-go。
答案 1 :(得分:0)
只需在解组时指定Foos
package main
import "fmt"
import "encoding/json"
type Foo struct {
Id uint64 `json:"id"`
Name string `json:"name"`
}
type BaseResult struct {
Error string `json:"error"`
}
type FooResult struct {
BaseResult
Foos []Foo
}
func main() {
// Simple and works.
structBody := []byte(`{"id": 1,"name": "foo"}`)
structResult := Foo{}
json.Unmarshal(structBody, &structResult)
fmt.Printf("%#v\n", structResult)
// Doesn't work.
arrayBody := []byte(`[{"id": 1,"name": "foo"},{"id": 2,"name": "bar"},{"id": 3,"name": "foobar"}]`)
arrayResult := FooResult{}
if err := json.Unmarshal(arrayBody, &arrayResult.Foos); err != nil {
arrayResult.BaseResult.Error = string(arrayBody)
}
fmt.Printf("%#v\n", arrayResult)
}