从main访问Inner Scope中的Struct数据并在Golang中将其保存到csv

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)
}