如何将JSON对象数组转换为Go中具有默认值的结构数组?
我正在开发一个GoAPI,它可以接收由JSON对象数组组成的POST。该职位的结构将类似于:如何将JSON对象数组转换为Go中具有默认值的结构数组?,json,go,struct,slice,Json,Go,Struct,Slice,我正在开发一个GoAPI,它可以接收由JSON对象数组组成的POST。该职位的结构将类似于: [ { "name":"Las Vegas", "size":14 }, { "valid": false, "name":"Buffalo", "size":63 } ] var allMap []map[string]interface{} var structs []Data for _, item := range allMap {
[
{
"name":"Las Vegas",
"size":14
},
{
"valid": false,
"name":"Buffalo",
"size":63
}
]
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
假设我有以下结构:
type Data {
Valid bool
Name string
Size float64
}
我想创建一组数据
s,并将Valid
设置为true
,只要它在JSON中没有实际指定为false
。如果我只做一个,我可以用,但是做一个未知数量的,我唯一能想到的是:
[
{
"name":"Las Vegas",
"size":14
},
{
"valid": false,
"name":"Buffalo",
"size":63
}
]
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
现在,我实际使用的结构有14个字段,其中一些字段有我想要指定的默认值,其他字段可以留空,但所有字段都必须使用这种方法进行迭代
有更好的方法吗?您可以使用该类型延迟对某些JSON文本值进行解组。如果您使用这种类型,那么JSON文本将存储在其中而不进行解组(因此您可以在以后根据需要解组此片段)
因此,在您的案例中,如果您试图将这些RawMessage
解组成一个片段,您可以使用您在问题中链接的技术,即您可以迭代原始值片段(每个数据的JSON文本),创建一个数据
结构,其中包含您希望作为缺失值默认值的值,并将一个切片元素解组到这个准备好的结构中。就这些
看起来是这样的:
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)
}
}
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)
}
}
试穿一下
注释/变体
为了提高效率(避免复制结构),您还可以在上面的示例中将allData
设置为指针片,如下所示:
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)
}
}
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)
}
}
如果希望继续使用非指针,为了提高效率,可以在切片元素本身中“准备”所需的默认值,如下所示:
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)
}
}
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)
}
}
您可以在类型上提供一个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
}
类型<代码>数据DAT/代码>简单地存在,这样我们就可以调用<代码> JSON。Unmarshal(j,& tMP)< /Cord>并获得原始未被重写的行为,而不是调用我们已经在中间的<代码> unMalSaljsS/<代码>方法。我们可以使用您已经链接到的技巧在
tmp
上设置默认值。然后在解组完成后,我们可以将tmp
转换为Data
,因为毕竟Data
和\u Data
实际上是同一类型的
使用这种方法,您可以
var structs []Data
err := json.Unmarshal(input, &structs)
(或者类似地使用json.Decoder
),让它按照您想要的方式工作。非常出色,谢谢。这可能是一个幼稚的问题,指针切片与结构切片相比,什么更有效?无论哪种方式,代码都使用引用,如果是指针,则当您为切片元素赋值时,它只复制指针(4或8字节)。如果slice包含非指针,则为slice元素赋值(例如,allData[i]=&Data{Valid:true}
)会复制整个结构,如果您的结构很大(您说它有14个字段),那么如果结构的大小是200字节,赋值会复制200字节。