一尘不染

使用特定顺序序列化地图

go

我有一个使用字符串作为键和值的映射。我有一个键数组,用于指定地图值的顺序。

我想将该映射序列化为JSON,但要保持数组上定义的顺序。

这里有一个示例代码:http :
//play.golang.org/p/A52GTDY6Wx

我想将其序列化为:

{
  "name": "John",
  "age": "20"
}

但是,如果我直接序列化地图,则密钥按字母顺序排列:

{      
  "age": "20",
  "name": "John"
}

我可以将其序列化为地图数组,从而保持顺序,但是会生成很多不需要的字符:

[
  {
    "name": "John"
  },
  {
    "age": "20"
  }
]

在我的真实代码中,我需要序列化在文本文件中指定的数据库查询的结果,并且需要维护列的顺序。我 不能 使用结构,因为在编译时这些列是未知的。

编辑:我不需要稍后以指定的顺序读取JSON。生成的JSON是供人们阅读的,因此我只希望它对人类尽可能可读。

我可以使用自定义格式,但是JSON非常适合我。

谢谢!


阅读 227

收藏
2020-07-02

共1个答案

一尘不染

对于您实际上根本不需要使用的特定要求json.Marshal,您可以像这样简单地实现自己的功能:

type OrderedMap map[string]string

func (om OrderedMap) ToJson(order ...string) string {
    buf := &bytes.Buffer{}
    buf.Write([]byte{'{', '\n'})
    l := len(order)
    for i, k := range order {
        fmt.Fprintf(buf, "\t\"%s\": \"%v\"", k, om[k])
        if i < l-1 {
            buf.WriteByte(',')
        }
        buf.WriteByte('\n')
    }
    buf.Write([]byte{'}', '\n'})
    return buf.String()
}
func main() {
    om := OrderedMap{
        "age":  "20",
        "name": "John",
    }
    fmt.Println(om.ToJson("name", "age"))
}
2020-07-02