appendStruct
function is designed to run in multiple threads in order to collect and append DataItem
into DataContainer
. So far I can print the result from inner appendStruct
Q1: how to access and print container
from main
, Q2: save that struct data type to csv
from main
?
package main
import "fmt"
type DataItem struct {
name string
}
type DataContainer struct {
Items []DataItem
}
func (box *DataContainer) AddItem(item DataItem) []DataItem {
box.Items = append(box.Items, item)
return box.Items
}
func appendStruct() {
items := []DataItem{}
container := DataContainer{items}
item1 := DataItem{name: fmt.Sprintf("Item1")}
item2 := DataItem{name: fmt.Sprintf("Item2")}
container.AddItem(item1)
container.AddItem(item2)
var ss = fmt.Sprintf("", container)
fmt.Println(ss)
}
func main() {
appendStruct()
}
OUTPUT from go run test.go
is:
%!(EXTRA main.DataContainer={[{Item1} {Item2}]})
re Q1. "encoding/csv"
has to implement string interface [][]string
there is a hint how to approach it in Write struct to csv file but lacks implementation example.
In appendStruct
, container
is a local variable, so it's not accessible outside that function call. You could return it, which would make it accessible from the caller (in this case, main
):
func appendStruct() DataContainer {
//...
return container
}
func main() {
container := appendStruct()
}
The answer you linked is an excellent starting point. A code example shouldn't really be necessary - they're basically recommending that you create a helper method/function that takes all the fields of the struct and puts them into a slice in whatever order you want them to appear in the CSV, e.g.:
func (c DataItem) ToSlice() []string {
row := make([]string, 1, 1) // Since you only have 1 field in the struct
row[0] = c.name
return row
}
Then you can loop over these to write them to a CSV file.
The error output you're getting is because you're using Sprintf
, which expects a format string as the first parameter with a reference for each other argument. You're passing an empty format string, which would only work with no other arguments (and be pointless). Perhaps you meant Sprintf("%v", container)
or just Sprint(container)
?
Thank you @Adrian, your answer was very helpful. Below is working code:
package main
import (
"fmt"
"os"
"encoding/csv"
"log"
)
type DataItem struct {
name string
}
type DataContainer struct {
Items []DataItem
}
func (box *DataContainer) AddItem(item DataItem) []DataItem {
box.Items = append(box.Items, item)
return box.Items
}
func appendStruct() DataContainer{
items := []DataItem{}
container := DataContainer{items}
item1 := DataItem{name: fmt.Sprintf("Item1")}
item2 := DataItem{name: fmt.Sprintf("Item2")}
container.AddItem(item1)
container.AddItem(item2)
return container
}
func (c DataItem) ToSlice() []string {
row := make([]string, 1, 1)
row[0] = c.name
return row
}
func checkError(message string, err error) {
if err != nil {
log.Fatal(message, err)
}
}
func main() {
container := appendStruct()
var ss = fmt.Sprint(container)
println(ss)
file, err := os.Create("result.csv")
checkError("Cannot create file", err)
defer file.Close()
w := csv.NewWriter(file)
for _, record := range container.Items {
values := record.ToSlice()
if err := w.Write(values); err != nil {
log.Fatalln("error writing record to csv:", err)
}
}
w.Flush()
if err := w.Error(); err != nil {
log.Fatal(err)
}