英文:
How to embed a map into a struct so that it has a flat json representation
问题
为了创建一个类似表格的结构,我在之前的应用程序中以以下格式序列化了我的行数据:
{ "key1": "...", "key2": "...", "15/04": 1.3, "15/05": 1.2, .... "17/08": 0.8 }
现在我正在尝试使用Go语言重写它,以便通过实践来学习这门语言。在Go中,可以通过将两个结构体嵌入到另一个结构体中来组合它们。该结构体的序列化JSON将具有扁平的结构,即结果JSON对象将具有第一个和第二个结构体字段的并集,而不是嵌套。这是一个示例:https://play.golang.org/p/jbJykip7pw(来自http://attilaolah.eu/2014/09/10/json-and-struct-composition-in-go/)
我猜想我也可以将一个map嵌入到一个结构体中,这样我就可以使用以下类型定义来序列化上述JSON:
type Row struct {
key1 string
key2 string
RowData
}
type RowData map[string]float64
...
func main() {
row := Row{
"...",
"...",
RowData{
"15/04": 1.3, "15/05": 1.2, .... "17/08": 0.8,
},
}
}
但是这样在我的Row
对象中创建了一个名为RowData
的字段,而不是将RowData
中的条目追加到我期望的扁平JSON对象中:
{ "key1": "...", "key2": "...", "RowData": { "15/04": 1.3, "15/05": 1.2, .... "17/08": 0.8 } }
我想知道是否有一种方法可以将map或slice嵌入到结构体中,以便生成的JSON对象是扁平的,而无需在Row
类型上定义MarshalJSON
函数?
英文:
In order to create a table-like structure, I serialized my row data in following format in my previous application:
{ "key1": "...", "key2": "...", "15/04": 1.3, "15/05": 1.2, .... "17/08": 0.8 }
Now I am trying to rewrite it in Go in order to learn the language with hands-on experience. In Go, one can compose two structs together by embedding them into another struct. The marshalled json out of that struct will have a flat structure, i.e. the resulting json object will have union of fields of first and second structs without nesting. Here is an example: https://play.golang.org/p/jbJykip7pw (from http://attilaolah.eu/2014/09/10/json-and-struct-composition-in-go/)
I guessed I could also embed a map into a struct so that I can marshall above json using following type definitions:
type Row struct {
key1 string
key2 string
RowData
}
type RowData map[string]float64
...
func main() {
row := Row{
"...",
"...",
RowData{
"15/04": 1.3, "15/05": 1.2, .... "17/08": 0.8,
},
}
}
But this created a field 'RowData' field in my 'Row' object, instead of appending entries in the RowData into my desired flat json object:
{ "key1": "...", "key2": "...", "RowData": { "15/04": 1.3, "15/05": 1.2, .... "17/08": 0.8 } }
I would like to know, if there is a way to embed maps or slices into a struct so that resulting json object is flat, without defining a MarshalJSON
function on type Row
?
答案1
得分: 8
简短的回答是不可以。该语言不允许在结构体中嵌入切片或映射类型。
你可以使用map[string]interface{}
。在其他地方处理"key1"和"key2"的值为字符串,而其他值为浮点数。这是你能得到该输出的唯一方式。你可以将问题复杂化(比如转换成类似你的类型),但如果你不想实现MarshalJSON
,那么只有使用map[string]interface{}
才能得到你想要的结果。
英文:
The short answer is no. The language does not allow you to embed either type (slice or map) in a struct.
Just use a map[string]interface{}
. Deal with the fact that the values for "key1" and "key2" are strings and everything else is a float somewhere else. That's really the only way you're getting that output. You can make the problem as complicated as you'd like beyond this (like transform into a type more like yours or something) but if you're averse to implementing MarshalJSON
the only model which will produce the results you want is map[string]interface{}
答案2
得分: -2
我知道已经有一个被接受的答案了,但实际上你可以得到指定的“期望的扁平 JSON 对象”。
"RowData" 不完全是一个 map[string]float
;获取它的类型将得到 "main.RowData"(如果它在 main 包中)。它可以嵌入在一个结构体中。以下是从原始帖子中改编的示例代码:
package main
import (
"encoding/json"
"fmt"
)
type Row struct {
Key1 string
Key2 string
RowData
}
type RowData map[string]float64
func main() {
row := Row{
RowData: make(map[string]float64),
}
row.RowData["15/04"] = 1.3
row.RowData["15/05"] = 1.2
row.RowData["17/08"] = 0.8
row.Key1 = "value one"
row.Key2 = "value two"
flatJSON, _ := json.Marshal(row)
fmt.Println(string(flatJSON))
}
这将输出:
{"Key1":"value one","Key2":"value two","RowData":{"15/04":1.3,"15/05":1.2,"17/08":0.8}}
为了能够导出字段名,它们必须是大写的,但你可以使用结构体标签使它们与问题中指定的字符串完全匹配。
英文:
I know there is an accepted answer already but actually you can get the specified "desired flat json object."
"RowData" is not exactly a map[string]float
; getting it's type will yield "main.RowData" (if this is in package main). And it can be embedded in a struct. Take this example, adapted from the original post:
package main
import (
"encoding/json"
"fmt"
)
type Row struct {
Key1 string
Key2 string
RowData
}
type RowData map[string]float64
func main() {
row := Row{
RowData: make(map[string]float64),
}
row.RowData["15/04"] = 1.3
row.RowData["15/05"] = 1.2
row.RowData["17/08"] = 0.8
row.Key1 = "value one"
row.Key2 = "value two"
flatJSON, _ := json.Marshal(row)
fmt.Println(string(flatJSON))
}
That will yield:
{"Key1":"value one","Key2":"value two","RowData":{"15/04":1.3,"15/05":1.2,"17/08":0.8}}
The field names will have to be capitals in order to be exported but you can make them match the exact string specified in the question using struct tags.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论