Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert arbitrary Golang interface to byte array

I'm trying to write a hash that will accept all datatypes. Once in the function, I handle the data as a byte array. I'm having trouble figuring out how to cast an arbitrary interface{} to a byte array.

I tried using the binary package but it seemed to depend on the type of data passed in. One of the parameters of the Write() fn (docs) required knowing the byte order of the parameter.

All datatype sizes are some multiple of a byte (even the bool), so this should be simple in theory.

Code in question below,

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 } 
like image 453
Nate Brennand Avatar asked Apr 11 '14 04:04

Nate Brennand


2 Answers

Other problems in my code led me away from the gob package earlier, turns out it was the proper way as @nvcnvn suggested. Relevant code on how to solve this issue below:

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 } 
like image 170
Nate Brennand Avatar answered Sep 16 '22 11:09

Nate Brennand


Another way to convert interface{} to []bytes is to use a fmt package.

/* * Convert variable `key` from interface{} to []byte */  byteKey := []byte(fmt.Sprintf("%v", key.(interface{}))) 

fmt.Sprintf converts interface value to string.
[]byte converts string value to byte.

※ Note ※ This method does not work if interface{} value is a pointer. Please find @PassKit's comment below.

like image 20
Midori Avatar answered Sep 18 '22 11:09

Midori