在golang中迭代嵌套结构并在切片字符串片段中存储值

问题描述 投票:0回答:1

我有一个嵌套的结构,我需要遍历字段并将其存储在切片的字符串切片中。然后,将其输出到csv文件。现在的问题是我手动访问结构中的每个字段并将其存储在切片界面切片中,但我的实际代码有100个字段,因此手动调用每个字段没有意义。此外,在写入csv文件时遇到以下错

//      for _, value := range output {
//          err := writer.Write(value) //ERROR: can't use value (type []interface{}) as type []string in argument to writer.Write (build)
//          checkError("Failed write to file", err)
//      }: 
`can't use value (type []interface{}) as type []string in argument to writer.Write (build)`

码:

type ApiStruct struct {
    Response []struct { //100 more fields
        A int         `json:"a"`
        B interface{} `json:"b"`
        C bool        `json:"c"`
        D string      `json:"d"`
        E int         `json:"e"`
        F float64     `json:"f"`
        G []string    `json:"g"`
        H bool        `json:"h"`
        I interface{} `json:"i"`
    } `json:"response"`
}

func main() {
    output := api_call()
    for _, value := range output {
        fmt.Println(value)
    }

    // write_file(output)

}

func api_call() (api_data [][]interface{}) {

    api_response := `{
    "response": [{
            "a": 2,
            "b": null,
            "c": false,
            "d": "sdasdas",
            "e": 22,
            "f": -123.2131231,
            "g": ["string1", "string2"],
            "h": true,
            "i": null
        },
        {
            "a": 4,
            "b": null,
            "c": true,
            "d": "sd",
            "e": 22,
            "f": 1223.2131231,
            "g": ["string3", "string4"],
            "h": true,
            "i": null
        }
    ]
  }`

    var d ApiStruct
    err := json.Unmarshal([]byte(api_response), &d)

    if err != nil {
        log.Fatal(err)
    }

    //instead of manually creating the headers or row lables for CSV output, want to know if there's a way to iterate through the key values in the struct
    api_data = append(api_data, []interface{}{"A", "B", "C", "D", "E", "F", "G", "H", "I"})

    for _, v := range d.Response {
        api_data = append(api_data, []interface{}{v.A, v.B, v.C, v.D, v.E, v.F, v.G, v.H, v.I})

        /*
            I want to do a for loop on those fields and store values in an array like this or any other way that's easier to store in a csv file.
            Instead of accessing each field individually (v.A, v.B), I want to iterate through the fields because
            I have 100 fields in the struct so doesn't make sense to do v.A, etc 100 times.
            Also, I am not sure if I can range over the interface slice of slice and store it in a csv file. Think it needs to be a string slice of slice [][]string.
            Maybe need to convert interface slice of slice: [][]interface{} to string slice of slice: [][]string

        */

    }

    return
}

请参阅以下链接以获取代码中的更多详细信息/评论:

https://play.golang.org/p/OEdi7Dfm_KL

如果有什么不清楚,请告诉我!任何帮助表示赞赏!

csv go struct slice
1个回答
2
投票

您可以使用reflect package以编程方式处理结构的字段,尤其是TypeValue类型。例如:

type Foo struct {
  A int
  B bool
  C string
  D float64
  E interface{}
}

func main() {
  f := Foo{1, true, "foo", 3.45, nil}
  t := reflect.TypeOf(f)
  v := reflect.ValueOf(f)

  for i := 0; i < v.NumField(); i++ {
    fmt.Printf("OK: %q -> %#v\n", t.Field(i).Name, v.Field(i))
  }
  // OK: "A" -> 1
  // OK: "B" -> true
  // OK: "C" -> "foo"
  // OK: "D" -> 3.45
  // OK: "E" -> interface {}(nil)
}

使用上面演示的字段名称和值,您可以生成用于csv package生成CSV的字符串:

func (f Foo) ValueStrings() []string {
  v := reflect.ValueOf(f)
  ss := make([]string, v.NumField())
  for i := range ss {
    ss[i] = fmt.Sprintf("%v", v.Field(i))
  }
  return ss
}

func main() {
  foos := []Foo{Foo{1, true, "foo", 2.34, nil}, Foo{2, false, "bar", 3.45, 1234}}
  w := csv.NewWriter(os.Stdout)

  // Write the CSV header.
  t := reflect.TypeOf(foos[0])
  names := make([]string, t.NumField())
  for i := range names {
    names[i] = t.Field(i).Name
  }
  if err := w.Write(names); err != nil {
    panic(err)
  }

  // Write the CSV rows.
  for _, foo := range foos {
    if err := w.Write(foo.ValueStrings()); err != nil {
      panic(err)
    }
  }
  w.Flush()

  if err := w.Error(); err != nil {
    panic(err)
  }
}
// A,B,C,D,E
// 1,true,foo,2.34,<nil>
// 2,false,bar,3.45,1234
© www.soinside.com 2019 - 2024. All rights reserved.