我正在为API进行Go包装,我注意到其中两个JSON字段在没有任何数据时保持为空。 基本上,API会在给定的URL上返回一组信息,如果至少访问过一次,一切都会好起来的,我得到了一个完整的json,然后将其解编为一个结构:
{
"stats":{
"status":1,
"date":"09.07.2019",
"title":"Test",
"devices":{
"dev":[
{
"tag":"Desktop"
}
],
"sys":[
{
"tag":"GNU/Linux "
},
{
"tag":"Windows 10"
}
],
"bro":[
{
"tag":"Firefox 67.0"
},
{
"tag":"Chrome 62.0"
}
]
},
"refs":[
{
"link":"www.google.com"
}
]
}
}
这是我正在使用的结构:
type Stats struct {
Stats struct {
Status int `json:"status"`
Date string `json:"date"`
Title string `json:"title"`
Devices struct {
Dev []struct {
Tag string `json:"tag"`
} `json:"dev"`
Sys []struct {
Tag string `json:"tag"`
} `json:"sys"`
Bro []struct {
Tag string `json:"tag"`
} `json:"bro"`
} `json:"devices"`
Refs []struct {
Link string `json:"link"`
} `json:"refs"`
} `json:"stats"`
}
提供新的网址后,事情就会变得有些奇怪:
{
"stats": {
"status": 1,
"date": "09.07.2019",
"title": "Test2",
"devices": [
],
"refs": [
]
}
}
如您所见,字段“ dev”,“ sys”和“ bro”只是消失了,因为它们没有被使用,当我尝试将JSON解组为同一结构时,我得到了json: cannot unmarshal array into Go struct field Stats.device of type [...]
我尝试使用两种不同的结构来处理两个响应,但是我敢肯定,有一种方法可以仅用一个结构就优雅地处理它们。
任何帮助将不胜感激,谢谢!
答案 0 :(得分:0)
我终于设法通过一个丑陋的解决方法来使其工作。 我将结构更改为
type Stats struct {
Status int `json:"status"`
Date string `json:"date"`
Title string `json:"title"`
Devices interface{} `json:"devices"`
Refs interface{} `json:"refs"`
}
然后,在两种情况下,我最终都可以解组JSON,但是在传递对象时得到map[string]interface{}
,在传递空数组时得到空interface{}
。为了解决这种矛盾,我只是检查数据类型并强制使用JSON中间转换,以便将map[string]interface{}
值解包到自定义Devices
结构中:
// Devices contains devices information
type Devices struct {
Dev []struct {
Tag string `json:"tag"`
Clicks string `json:"clicks"`
} `json:"dev"`
Sys []struct {
Tag string `json:"tag"`
Clicks string `json:"clicks"`
} `json:"sys"`
Bro []struct {
Tag string `json:"tag"`
Clicks string `json:"clicks"`
} `json:"bro"`
}
我使用的算法如下:
//ForceDevicesToRightType uses a json conversion as intermediary for filling the Stats.Devices
// struct with map[string]interface{} values
func ForceDevicesToRightType(dev interface{}) (Devices, error) {
temp, err := json.Marshal(dev)
if err != nil {
return Devices{}, err
}
// Use a temporary variable of the right type
var devices Devices
err = json.Unmarshal(temp, &devices)
if err != nil {
return Devices{}, err
}
return devices, nil
}
// ForceRefsToRightType uses a json conversion as intermediary for filling the Stats.Refs
// struct with map[string]interface{} values
func ForceRefsToRightType(refs interface{}) (Refs, error) {
temp, err := json.Marshal(refs)
if err != nil {
return Refs{}, err
}
// Use a temporary variable of the right type
var references Refs
err = json.Unmarshal(temp, &references)
if err != nil {
return Refs{}, err
}
return references, nil
}
由于编译器知道“设备”和“引用”字段均为interface{}
,所以在转换后我不能简单地访问任何方法,因此我只需对类型进行正确的转换就可以了。
例如,如果我想访问Dev子结构,这是正确的方法:
y, _ := GetStats()
fmt.Println(y.Devices.(Devices).Dev)
这很丑,但是行得通。
非常感谢您的帮助,希望这种方法可以使您免于头痛!