结构中的唯一哈希

问题描述 投票:1回答:2

我想从结构数组生成一个唯一的哈希。订单可能不同,但值相同。

例:

type MyStruct struct {
   ID string
   Parameters map[string]interface{}
}

arr:= []MyStruct{MyStruct{ID: "test", Parameters: map[string]interface{}{"key": true, "key2": "value"} }, MyStruct{ID: "test2", Parameters: map[string]interface{}{"key2": "value", "key": true} }}
//The order is different even inside the Parameters fields

arr:= []MyStruct{MyStruct{ID: "test2", Parameters: map[string]interface{}{"key2": "value", "key": true} },MyStruct{ID: "test", Parameters: map[string]interface{}{"key": true, "key2": "value"} }}

在这两种情况下,散列应该是相同的,因为结构内部的值是相同的。

编辑:基本上这个想法是为缓存生成一个唯一的哈希!我想结合每个结构的单个哈希!

go struct hash
2个回答
2
投票

您可以通过将数组序列化为字节数组,然后计算字节数组的md5总和来完成此操作。由于md5 sum是字节的散列和,因此顺序无关紧要。

要序列化数组的每个元素,您可以使用json.Marshal,它适用于任何类型的struct

哈希函数看起来像这样:

func Hash(arr []SomeStruct) [16]byte {
    arrBytes := []byte{}
    for _, item := range arr {
        jsonBytes, _ := json.Marshal(item)
        arrBytes = append(arrBytes, jsonBytes...)
    }
    return md5.Sum(arrBytes)
}

您可以运行工作示例程序here

func main() {
    arr1 := []SomeStruct{
        {
            param1: "abc",
            param2: 3,
        },
        {
            param1: "def",
            param2: 5,
        }, {
            param1: "deg",
            param2: 0,
        },
    }
    arr2 := []SomeStruct{
    {
            param1: "deg",
            param2: 0,
        },
        {
            param1: "def",
            param2: 5,
        },
        {
            param1: "abc",
            param2: 3,
        },
    }

    fmt.Printf("Hash1: %x\n", Hash(arr1))
    fmt.Printf("Hash2: %x\n", Hash(arr2))

}

func Hash(arr []SomeStruct) [16]byte {
    arrBytes := []byte{}
    for _, item := range arr {
        jsonBytes, _ := json.Marshal(item)
        arrBytes = append(arrBytes, jsonBytes...)
    }
    return md5.Sum(arrBytes)
}

哪个会输出:

Hash1: d065fee603fdcf75115204ec65310e1c
Hash2: d065fee603fdcf75115204ec65310e1c

2
投票

Feng有一个观点,接受的答案不起作用,不仅因为结构中没有导出的字段,而且MD5哈希的方式确实具有顺序意义,请参阅RFC 1321 3.4

不确定功效,但我有一些工作,通过使用encoding/gobbytes代表在Compare中使用的哈希传递切片作为字节。

Playground

package main

import (
    "bytes"
    "encoding/gob"
    "fmt"
)

type S struct {
    K1 string
    K2 int
}

func main() {
    sa := []S{{ K1: "foo", K2: 1}, {K1: "bar", K2: 2}, {K1: "baz", K2: 3,}}
    sb := []S{{ K1: "baz", K2: 3}, {K1: "bar", K2: 2}, {K1: "foo", K2: 1,}}
    sc := []S{}

    a := Hash(sa)
    b := Hash(sb)
    c := Hash(sc)

    fmt.Println(Compare(a, b))
    fmt.Println(Compare(a, c))
}

func Compare(a, b []byte) bool {
    a = append(a, b...)
    c := 0
    for _, x := range a {
        c ^= int(x)
    }
    return c == 0
}

func Hash(s []S) []byte {
    var b bytes.Buffer
    gob.NewEncoder(&b).Encode(s)
    return b.Bytes()
}
© www.soinside.com 2019 - 2024. All rights reserved.