我有一个嵌套的结构,我需要迭代遍历字段并将其存储在切片的字符串切片中。然后,将其输出到csv文件。 现在的问题是我手动访问结构中的每个字段并将其存储在切片界面切片中,但我的实际代码有100个字段,因此手动调用每个字段没有意义。 此外,无法将切片接口切片存储到csv,因为当写入输出为[] []接口{}
的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
如果有什么不清楚,请告诉我!任何帮助表示赞赏!
答案 0 :(得分:2)
您可以使用reflect
package以编程方式处理结构的字段,尤其是Type
和Value
类型。例如:
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