You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让json.Marshal输出一致字节数组?针对map哈希需求

解决map[string]interface{}的稳定哈希问题

要生成map[string]interface{}的稳定哈希,核心是先将嵌套结构标准化为有序形式,再序列化为字节数组。直接用json.Marshal会因为map键顺序、数组元素顺序变化导致字节数组不一致,因此需要递归处理所有嵌套结构:

核心思路

  • Map处理:提取所有键并排序,按排序后的键依次处理每个值(递归标准化)
  • 切片/数组处理:先递归标准化每个元素,再将元素转换为可比较的形式(如JSON字符串)进行排序
  • 基本类型:直接保留,无需额外处理

实现代码

标准化函数

package main

import (
    "encoding/json"
    "fmt"
    "sort"
)

func normalize(v interface{}) interface{} {
    switch val := v.(type) {
    case map[string]interface{}:
        // 排序map的键
        keys := make([]string, 0, len(val))
        for k := range val {
            keys = append(keys, k)
        }
        sort.Strings(keys)
        // 按排序后的键构建有序结构
        ordered := make([]interface{}, 0, len(val)*2)
        for _, k := range keys {
            ordered = append(ordered, k, normalize(val[k]))
        }
        return ordered
    case []interface{}:
        // 先递归标准化每个元素
        normalizedElems := make([]interface{}, len(val))
        for i, elem := range val {
            normalizedElems[i] = normalize(elem)
        }
        // 按元素的JSON字符串排序,保证顺序一致
        sort.Slice(normalizedElems, func(i, j int) bool {
            iBytes, _ := json.Marshal(normalizedElems[i])
            jBytes, _ := json.Marshal(normalizedElems[j])
            return string(iBytes) < string(jBytes)
        })
        return normalizedElems
    // 基本类型直接返回
    case int, int8, int16, int32, int64,
        uint, uint8, uint16, uint32, uint64,
        float32, float64, string, bool:
        return val
    // 其他类型可按需扩展(如time.Time)
    default:
        return val
    }
}

测试代码

func main() {
    data := map[string]interface{}{
        "id":    "124",
        "name":  "name",
        "count": 123456,
        "sites": []map[string]interface{}{
            {
                "name":  "123445",
                "count": 234324,
                "id":    "wersfs",
            },
            {
                "id":    "sadcacasca",
                "name":  "sdvcscds",
                "count": 22,
            },
        },
        "list": []int{5, 324, 123, 123, 123, 14, 34, 52, 3},
    }

    data1 := map[string]interface{}{
        "name": "name",
        "id":   "124",
        "sites": []map[string]interface{}{
            {
                "id":    "sadcacasca",
                "count": 22,
                "name":  "sdvcscds",
            },
            {
                "count": 234324,
                "name":  "123445",
                "id":    "wersfs",
            },
        },
        "count": 123456,
        "list":  []int{123, 14, 34, 52, 3, 5, 324, 123, 123},
    }

    // 标准化后再序列化
    normalizedData := normalize(data)
    normalizedData1 := normalize(data1)

    jsonStr, _ := json.Marshal(normalizedData)
    jsonStr1, _ := json.Marshal(normalizedData1)

    fmt.Println("标准化后的JSON是否一致:", string(jsonStr) == string(jsonStr1)) // 输出true
}

关键说明

  • Map标准化:将无序的map转换为[key1, value1, key2, value2,...]的有序切片,确保键顺序固定
  • 切片排序:通过将元素转换为JSON字符串进行比较,兼容所有可序列化的嵌套结构,保证内容相同的元素排序后位置一致
  • 性能优化:如果对性能要求极高,可以针对特定类型(如int、string)编写专门的比较逻辑,避免JSON序列化的开销

内容的提问来源于stack exchange,提问作者Sid P Tkf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 22:35:27