Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将JSON对象数组转换为Go中具有默认值的结构数组?_Json_Go_Struct_Slice - Fatal编程技术网

如何将JSON对象数组转换为Go中具有默认值的结构数组?

如何将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 {

我正在开发一个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 {
  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字节。