将任意 Golang 接口转换为字节数组

Posted

技术标签:

【中文标题】将任意 Golang 接口转换为字节数组【英文标题】:Convert arbitrary Golang interface to byte array 【发布时间】:2014-05-25 02:09:12 【问题描述】:

我正在尝试编写一个可以接受所有数据类型的哈希。进入函数后,我将数据作为字节数组处理。我无法弄清楚如何将任意 interface 转换为字节数组。

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

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

下面有问题的代码,

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 "encoding/gob" 怎么样?可以用吗? @nvcnvn,似乎正在工作。我早些时候尝试过,但现在我意识到小值的散列存在弱点(0-62 是否相同?)。我改变了我正在使用的范围,它现在似乎可以工作。谢谢! 修复了哈希 fn 中的错误,更新代码在这里找到:gist.github.com/natebrennand/10442587 【参考方案1】:

我代码中的其他问题导致我早先离开了gob 包,结果证明这是@nvcnvn 建议的正确方法。下面是如何解决这个问题的相关代码:

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 初学者来说,这真的很有帮助! @RudiStrydom 将映射转换为字节以节省空间?这就是我发现它有用的地方。 当时,我正在尝试编写一个可处理任意数据结构的布隆过滤器。因此,通过将任何 struct/map/slice 转换为[]byte,我可以将字节切片处理为哈希。 gist.github.com/natebrennand/10442587【参考方案2】:

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

/*
* 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 在他的评论中所说的

以上是关于将任意 Golang 接口转换为字节数组的主要内容,如果未能解决你的问题,请参考以下文章

将字节数组转换为 Golang 中的 syscall.InotifyEvent 结构

swift 将任意长度的字节数组转换为Swift Int

golang 在go中将字节数组转换为int

使用 ByteBuffer 将 n 字节数组转换为整数

如何在 C++ 中将字节数组转换为十六进制字符串?

Java将字节数组转换为十六进制字节数组[重复]