How to embed a map into a struct so that it has a flat json representation

守給你的承諾、 提交于 2019-12-07 16:36:16

问题


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:


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:


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.



来源:https://stackoverflow.com/questions/31036343/how-to-embed-a-map-into-a-struct-so-that-it-has-a-flat-json-representation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!