2014-04-11 12 views
17

Próbuję napisać skrót, który będzie akceptował wszystkie typy danych. Będąc w funkcji, traktuję dane jako tablicę bajtów. Mam problem z ustaleniem, jak rzutować arbitralny interface{} do tablicy bajtowej.Konwertuj arbitralny interfejs Golang na tablicę bajtów

Próbowałem użyć pakietu binarnego, ale wydawało się, że zależy to od rodzaju przekazanych danych. Jeden z parametrów Write() fn (docs) wymagał znajomości kolejności bajtów parametru.

Wszystkie typy danych są wielokrotnością bajtu (nawet bool), więc powinno to być proste w teorii.

Kod mowa poniżej,

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 
} 
+3

Co powiecie na pkg "encoding/gob"? Czy możesz go użyć? – nvcnvn

+0

@nvcnvn, wydaje się działać. Próbowałem wcześniej, ale teraz zdaję sobie sprawę, że w haszu jest słabość na małych wartościach (0-62 są identyczne?). Zmieniłem zakres pracy, z którym pracowałem, teraz wydaje się działać. Dzięki! –

+0

poprawiono błędy w haszowaniu fn, zaktualizowany kod można znaleźć tutaj: https://gist.github.com/natebrennand/10442587 –

Odpowiedz

40

Inne problemy w moim kodu doprowadziło mnie od pakietu gob wcześniej, okazuje się, że to właściwa droga jak @nvcnvn sugerowane. Odpowiedni kod, aby rozwiązać ten problem poniżej:

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 
} 
+0

Możesz przyjąć własną odpowiedź jako odpowiedź na swoje pytanie :) – photoionized

+0

Ten i odwrotnie: https://play.golang.org/p/mJPMN1_KSv – sromku

+1

Byłoby miło mieć przykład pokazujący użycie tej metody. Dla wielu początkujących, takich jak ja, z Go, to naprawdę pomoże przydzielić! –

Powiązane problemy