我正在使用Go API,它可以接收由JSON对象数组组成的POST。 POST的结构如下所示:
[
{
"name":"Las Vegas",
"size":14
},
{
"valid": false,
"name":"Buffalo",
"size":63
}
]
我们说我有以下结构:
type Data {
Valid bool
Name string
Size float64
}
我想创建一堆Data
Valid
,true
设置为false
,只要它在JSON中没有实际指定为var allMap []map[string]interface{}
var structs []Data
for _, item := range allMap {
var data Data
var v interface{}
var ok bool
if v, ok := item["value"]; ok {
data.Valid = v
} else {
data.Valid = true
}
id v, ok := item["name"]; ok {
data.Name = v
}
...
structs = append(structs, data)
}
return structs
。如果我只做一个,我可以使用How to specify default values when parsing JSON in Go,但是为了做一个未知数量的它我唯一能够想出的就是:
{{1}}
现在我实际使用的结构有14个字段,其中一些有我想要分配默认值的值,有些可以留空,但是所有这些都必须通过使用这种方法进行迭代。
有更好的方法吗?
答案 0 :(得分:3)
您可以使用json.RawMessage
类型来推迟解组某些JSON文本值。如果你使用这种类型,那么JSON文本将被存储在其中而不需要解组(因此你可以随后解组这个片段)。
所以在你的情况下,如果你试图解组成这样的RawMessage
切片,你可以使用你在问题中链接的技术,即你可以迭代原始值的片段(这是每个Data
的JSON文本,创建一个Data
结构,其中包含您想要的值作为缺失值的默认值,并将切片元素解组到此准备好的结构中。这就是全部。
看起来像这样:
allJson := []json.RawMessage{}
if err := json.Unmarshal(src, &allJson); err != nil {
panic(err)
}
allData := make([]Data, len(allJson))
for i, v := range allJson {
// Here create your Data with default values
allData[i] = Data{Valid: true}
if err := json.Unmarshal(v, &allData[i]); err != nil {
panic(err)
}
}
在Go Playground上尝试。
备注/变体
为了提高效率(避免复制结构),您还可以使allData
成为上述示例中的一个指针片段,如下所示:
allData := make([]*Data, len(allJson))
for i, v := range allJson {
// Here create your Data with default values
allData[i] = &Data{Valid: true}
if err := json.Unmarshal(v, allData[i]); err != nil {
panic(err)
}
}
如果你想继续使用非指针,为了提高效率,你可以准备"准备"您希望切片元素本身的默认值,如下所示:
allData := make([]Data, len(allJson))
for i, v := range allJson {
// Here set your default values in the slice elements
// Only set those which defer from the zero values:
allData[i].Valid = true
if err := json.Unmarshal(v, &allData[i]); err != nil {
panic(err)
}
}
答案 1 :(得分:0)
你可以通过在你的类型上提供一个UnmarshalJSON
方法来做一个很好的技巧,使其透明并自动工作,即使你的类型是在结构或切片中找到的。
func (d *Data) UnmarshalJSON(j []byte) error {
type _Data Data // Dummy type to avoid infinite recursion in UnmarshalJSON
tmp := _Data{ // Set defaults here
Valid: true,
}
err := json.Unmarshal(j, &tmp)
if err != nil {
return err
}
*d = Data(tmp)
return nil
}
_Data
类型的存在只是为了让我们可以调用json.Unmarshal(j, &tmp)
并获取原始的未覆盖行为,而不是调用我们已经在其中的UnmarshalJSON
方法中间。我们可以使用您已链接到的技巧在tmp
上设置默认值。然后在解组完成后,我们可以将tmp
转换为Data
,因为毕竟Data
和_Data
的类型实际上是相同的。
鉴于此方法,您可以简单地
var structs []Data
err := json.Unmarshal(input, &structs)
(或同样使用json.Decoder
)并让它按照您想要的方式工作。