Accessing Struct Data in Inner Scope from main and save to csv in Golang

huangapple go评论82阅读模式
英文:

Accessing Struct Data in Inner Scope from main and save to csv in Golang

问题

appendStruct函数被设计为在多个线程中运行,以便将DataItem追加到DataContainer中。到目前为止,我可以从内部的appendStruct打印结果。问题1:如何从main函数中访问和打印container?问题2:如何将该结构体数据类型保存为csv文件?

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("%v", container)
	fmt.Println(ss)
}

func main() {

	appendStruct()

}

go run test.go的输出结果为:

%!(EXTRA main.DataContainer={[{Item1} {Item2}]})

关于问题1:main函数如何访问和打印container,你可以将container声明为全局变量,然后在main函数中直接访问和打印它。

关于问题2:encoding/csv包需要实现[][]string的字符串接口。在Write struct to csv file中有一个提示如何处理,但缺少实现示例。

英文:

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.

答案1

得分: 2

appendStruct函数中,container是一个局部变量,所以在该函数调用之外是无法访问的。你可以返回它,这样就可以从调用者(在这种情况下是main函数)中访问它:

func appendStruct() DataContainer {
    //...
    return container
}

func main() {
    container := appendStruct()
}

你链接的答案是一个很好的起点。实际上不需要一个代码示例 - 他们基本上建议你创建一个辅助方法/函数,将结构体的所有字段放入一个切片中,以你希望它们在CSV中出现的顺序,例如:

func (c DataItem) ToSlice() []string {
    row := make([]string, 1, 1) // 因为你的结构体只有一个字段
    row[0] = c.name
    return row
}

然后你可以循环遍历这些切片将它们写入CSV文件。

你得到的错误输出是因为你使用了Sprintf,它期望第一个参数是一个格式化字符串,并且有一个对应每个其他参数的引用。你传递了一个空的格式化字符串,这只适用于没有其他参数的情况(并且是无意义的)。也许你的意思是Sprintf("%v", container)或者只是Sprint(container)

英文:

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

答案2

得分: 0

谢谢@Adrian,你的答案非常有帮助。以下是可工作的代码:

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

以上是你要翻译的代码。

英文:

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

huangapple
  • 本文由 发表于 2017年8月3日 00:46:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/45466614.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定