英文:
Writing a struct's fields and values of different types to a file in Go
问题
我正在编写一个简单的程序,该程序从表单中接收输入,用接收到的数据填充一个结构体实例,然后将这些接收到的数据写入文件。
目前我有点困惑,不知道如何最好地遍历填充的结构体并将其内容写入文件。
所涉及的结构体包含3种不同类型的字段(int、string、[]string)。
我可以遍历它们,但无法获取它们的实际类型。
通过使用下面的代码和打印语句检查,我发现它们的类型都返回为结构体,而不是之前提到的字符串、整数等。
期望的输出格式是纯文本。
例如:
field_1="value_1"
field_2=10
field_3=["a", "b", "c"]
有人有什么想法吗?也许我完全走错了方向?
func (c *Config) writeConfigToFile(file *os.File) {
listVal := reflect.ValueOf(c)
element := listVal.Elem()
for i := 0; i < element.NumField(); i++ {
field := element.Field(i)
myType := reflect.TypeOf(field)
if myType.Kind() == reflect.Int {
file.Write(field.Bytes())
} else {
file.WriteString(field.String())
}
}
}
英文:
I'm writing a simple program that takes in input from a form, populates an instance of a struct with the received data and the writes this received data to a file.
I'm a bit stuck at the moment with figuring out the best way to iterate over the populated struct and write its contents to the file.
The struct in question contains 3 different types of fields (ints, strings, []strings).
I can iterate over them but I am unable to get their actual type.
Inspecting my posted code below with print statements reveals that each of their types is coming back as structs rather than the aforementioned string, int etc.
The desired output format is be plain text.
For example:
field_1="value_1"
field_2=10
field_3=["a", "b", "c"]
Anyone have any ideas? Perhaps I'm going about this the wrong way entirely?
func (c *Config) writeConfigToFile(file *os.File) {
listVal := reflect.ValueOf(c)
element := listVal.Elem()
for i := 0; i < element.NumField(); i++ {
field := element.Field(i)
myType := reflect.TypeOf(field)
if myType.Kind() == reflect.Int {
file.Write(field.Bytes())
} else {
file.WriteString(field.String())
}
}
}
答案1
得分: 2
为什么不使用内置的gob
包来存储你的结构体数值?
我使用它来将不同的结构体按行存储在文件中。在解码时,你可以测试类型转换或在包装器中提供提示,以便根据你的使用情况选择更快的方法。
在编码和解码时,你可以将每一行视为缓冲区。你甚至可以实时地对流进行gzip/zlib/compress、加密/解密等操作。
当你已经有一个经过打磨和护理的轮子可供使用时,没有必要重新发明轮子。
英文:
Why not use the built-in gob
package to store your struct values?
I use it to store different structures, one per line, in files. During decoding, you can test the type conversion or provide a hint in a wrapper - whichever is faster for your given use case.
You'd treat each line as a buffer when Encoding and Decoding when reading back the line. You can even gzip/zlib/compress, encrypt/decrypt, etc the stream in real-time.
No point in re-inventing the wheel when you have a polished and armorall'd wheel already at your disposal.
答案2
得分: 2
使用reflect.Value
上的Bytes
方法并不像你最初打算的那样起作用,你可以使用strconv
包或fmt
来格式化你的字段。
这里是使用fmt
的示例:
var s string
switch fi.Kind() {
case reflect.String:
s = fmt.Sprintf("%q", fi.String())
case reflect.Int:
s = fmt.Sprintf("%d", fi.Int())
case reflect.Slice:
if fi.Type().Elem().Kind() != reflect.String {
continue
}
s = "["
for j := 0; j < fi.Len(); j++ {
s = fmt.Sprintf("%s%q, ", s, fi.Index(i).String())
}
s = strings.TrimRight(s, ", ") + "]"
default:
continue
}
sf := rv.Type().Field(i)
if _, err := fmt.Fprintf(file, "%s=%s\n", sf.Name, s); err != nil {
panic(err)
}
Playground: https://play.golang.org/p/KQF3CicVzA
英文:
Instead of using the Bytes
method on reflect.Value
which does not work as you initially intended, you can use either the strconv
package or the fmt
to format you fields.
Here's an example using fmt
:
var s string
switch fi.Kind() {
case reflect.String:
s = fmt.Sprintf("%q", fi.String())
case reflect.Int:
s = fmt.Sprintf("%d", fi.Int())
case reflect.Slice:
if fi.Type().Elem().Kind() != reflect.String {
continue
}
s = "["
for j := 0; j < fi.Len(); j++ {
s = fmt.Sprintf("%s%q, ", s, fi.Index(i).String())
}
s = strings.TrimRight(s, ", ") + "]"
default:
continue
}
sf := rv.Type().Field(i)
if _, err := fmt.Fprintf(file, "%s=%s\n", sf.Name, s); err!= nil {
panic(err)
}
Playground: https://play.golang.org/p/KQF3CicVzA
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论