戈朗。映射到 JSON,但保留键顺序

Golang. Map to JSON, but preserve the key order

我有一个地图对象,当它使用 json.Marshal(myMapObjct) 序列化时,Golang 会按字母顺序对键进行排序,这会导致数据处理方式出现问题。一旦将 JSON 结构创建为字节片,保留键顺序很重要。是否有可能以这种方式序列化它,或者我是否需要为这种特定的边缘情况编写自己的序列化程序?

这是负责生成 JSON 结构的代码片段:

// serializedTraffic wraps around naturalTraffic and serializes map to string.
func serializedTraffic(payload string) (string, error) {
    trafficMap := naturalTraffic(string(payload))
    traffic, err := json.Marshal(trafficMap)
    return string(traffic), err
}

    // naturalTraffic obfuscates 'payload' into JSON-like structure.
func naturalTraffic(payload string) map[string]string {
    // Decide on how many keys there will be in the JSON structure.
    indexChar := 0
    maxChars := 126
    minChars := 16

    var jsonObject = make(map[string]string)

    // Build the JSON structure.
    for indexChar < len(payload) {
        rand.Seed(time.Now().UnixNano())
        chunkSize := rand.Intn(maxChars-minChars) + minChars
        if len(payload) < indexChar+chunkSize {
            chunkSize = len(payload) - indexChar
        }
        key := randomPopularWord()
        jsonObject[key] = base64.StdEncoding.EncodeToString([]byte(payload[indexChar : indexChar+chunkSize]))
        indexChar += chunkSize
    }

    return jsonObject
}

根据建议,我提供了一个不同的结构来修复代码。

    type elem struct{ key, val string }

    type object []elem

    func (o object) MarshalJSON() (out []byte, err error) {
        if o == nil {
            return []byte(`null`), nil
        }
        if len(o) == 0 {
            return []byte(`{}`), nil
        }

        out = append(out, '{')
        for _, e := range o {
            key, err := json.Marshal(e.key)
            if err != nil {
                return nil, err
            }
            val, err := json.Marshal(e.val)
            if err != nil {
                return nil, err
            }
            out = append(out, key...)
            out = append(out, ':')
            out = append(out, val...)
            out = append(out, ',')
        }
        // replace last ',' with '}'
        out[len(out)-1] = '}'
        return out, nil
    }

    // serializedTraffic wraps around naturalTraffic and serializes map to string.
    func serializedTraffic(payload string) (string, error) {
        trafficMap := naturalTraffic(string(payload))
        traffic, err := trafficMap.MarshalJSON()
        return string(traffic), err
    }

    // naturalTraffic obfuscates 'payload' into JSON-like structure.
    func naturalTraffic(payload string) object {
        // Decide on how many keys there will be in the JSON structure.
        indexChar := 0
        maxChars := 126
        minChars := 16

        var jsonObject object

        // Build the JSON structure.
        for indexChar < len(payload) {
            rand.Seed(time.Now().UnixNano())
            chunkSize := rand.Intn(maxChars-minChars) + minChars
            if len(payload) < indexChar+chunkSize {
                chunkSize = len(payload) - indexChar
            }
            key := randomPopularWord()
            jsonObject = append(jsonObject, elem{
                key: key,
                val: base64.StdEncoding.EncodeToString([]byte(payload[indexChar : indexChar+chunkSize])),
            })
            indexChar += chunkSize
        }

        return jsonObject
    }