我正在尝试编写一个将接受所有数据类型的哈希。 一旦进入函数,我将数据作为字节数组处理。 我在弄清楚如何将任意interface{}强制转换为字节数组时遇到麻烦。

我尝试使用二进制包,但它似乎取决于传入的数据类型。Write() fn(docs)的参数之一需要知道参数的字节顺序。

所有数据类型的大小都是字节的某个倍数(甚至是布尔值),因此理论上这应该很简单。

下面有问题的代码,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package bloom

import (
   "encoding/gob"
   "bytes"
)

// adapted from http://bretmulvey.com/hash/7.html
func ComputeHash(key interface{}) (uint, error) {
    var buf bytes.Buffer
    enc := gob.NewEncoder(&buf)
    err := enc.Encode(key)
    if err != nil {
        return 0, err
    }
    data := buf.Bytes()

    var a, b, c uint
    a, b = 0x9e3779b9, 0x9e3779b9
    c = 0;
    i := 0;

    for i = 0; i < len(data)-12; {
        a += uint(data[i+1] | data[i+2] << 8 | data[i+3] << 16 | data[i+4] << 24)
        i += 4
        b += uint(data[i+1] | data[i+2] << 8 | data[i+3] << 16 | data[i+4] << 24)
        i += 4
        c += uint(data[i+1] | data[i+2] << 8 | data[i+3] << 16 | data[i+4] << 24)

        a, b, c = mix(a, b, c);
    }

    c += uint(len(data))

    if i < len(data) {
        a += uint(data[i])
        i++
    }
    if i < len(data) {
        a += uint(data[i] << 8)
        i++
    }
    if i < len(data) {
        a += uint(data[i] << 16)
        i++
    }
    if i < len(data) {
        a += uint(data[i] << 24)
        i++
    }


    if i < len(data) {
        b += uint(data[i])
        i++
    }
    if i < len(data) {
        b += uint(data[i] << 8)
        i++
    }
    if i < len(data) {
        b += uint(data[i] << 16)
        i++
    }
    if i < len(data) {
        b += uint(data[i] << 24)
        i++
    }

    if i < len(data) {
        c += uint(data[i] << 8)
        i++
    }
    if i < len(data) {
        c += uint(data[i] << 16)
        i++
    }
    if i < len(data) {
        c += uint(data[i] << 24)
        i++
    }

    a, b, c = mix(a, b, c)
    return c, nil
}

func mix(a, b, c uint) (uint, uint, uint){
    a -= b; a -= c; a ^= (c>>13);
    b -= c; b -= a; b ^= (a<<8);
    c -= a; c -= b; c ^= (b>>13);
    a -= b; a -= c; a ^= (c>>12);
    b -= c; b -= a; b ^= (a<<16);
    c -= a; c -= b; c ^= (b>>5);
    a -= b; a -= c; a ^= (c>>3);
    b -= c; b -= a; b ^= (a<<10);
    c -= a; c -= b; c ^= (b>>15);

    return a, b, c
}
  • pkg"编码/目标"怎么样? 可以使用吗?
  • @nvcnvn,似乎正在工作。 我早些时候尝试过,但现在我意识到小值(0-62是否相同?)的哈希值存在缺陷。 我更改了我现在使用的范围,现在似乎可以使用。 谢谢!
  • 修复了哈希fn中的错误,可在此处找到更新的代码:gist.github.com/natebrennand/10442587

我代码中的其他问题使我较早离开了gob软件包,事实证明这是@nvcnvn建议的正确方法。 以下有关如何解决此问题的相关代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package bloom

import (
   "encoding/gob"
   "bytes"
)

func GetBytes(key interface{}) ([]byte, error) {
    var buf bytes.Buffer
    enc := gob.NewEncoder(&buf)
    err := enc.Encode(key)
    if err != nil {
        return nil, err
    }
    return buf.Bytes(), nil
}
  • 随意接受自己的答案作为问题的答案:)
  • 举个例子说明这个方法的用法会很高兴。 对于像Go这样的许多初学者来说,这确实有助于分配!

interface{}转换为[]bytes的另一种方法是使用fmt包。

1
2
3
4
5
/*
* Convert variable `key` from interface{} to []byte
*/

byteKey := []byte(fmt.Sprintf("%v", key.(interface{})))

fmt.Sprintf将接口值转换为字符串。
[] byte将字符串值转换为字节。

※注意※如果interface {}值为指针,则此方法不起作用。 请在下面找到@PassKit的评论。

  • 如果该接口是一个指针,您将获得一个内存地址,则可能会产生意想不到的结果。 play.golang.org/p/EgjvrqOyxEi
  • 在您的答案中值得一提的是@PassKit在他的评论中所说的