web-dev-qa-db-fra.com

Dans Go, comment puis-je convertir une structure en un tableau d'octets?

J'ai une instance d'une structure que j'ai définie et j'aimerais la convertir en un tableau d'octets. J'ai essayé [] byte (my_struct), mais cela n'a pas fonctionné. De plus, on m'a indiqué le paquet binaire , mais je ne suis pas sûr de la fonction à utiliser ni de la manière dont je devrais l'utiliser. Un exemple serait grandement apprécié.

23
abw333

Je suppose que vous voulez quelque chose comme la façon dont C gère cela. Il n'y a pas de moyen intégré pour le faire. Vous devrez définir vos propres sérialisation et désérialisation d'octets pour votre structure. Le paquet binaire vous aidera à encoder les champs de votre structure en octets que vous pouvez ajouter au tableau d'octets, mais vous serez responsable de la spécification des longueurs et des décalages dans le tableau d'octets contenant les champs de votre structure.

Vos autres options sont d'utiliser l'un des packages d'encodage: http://golang.org/pkg/encoding/ tels que gob ou json.

MODIFIER:

Comme vous le souhaitez pour créer un hachage, comme vous le dites dans votre commentaire, la chose la plus facile à faire est d'utiliser []byte(fmt.Sprintf("%v", struct)) comme ceci: http://play.golang.org/p/yY8mSdZ_kf

20
Jeremy Wall

Une solution possible est le package standard "encoding/gob". Le paquetage gob crée un codeur/décodeur capable de coder toute structure dans un tableau d'octets, puis de décoder ce tableau en une structure. Il y a un bon article, ici .

Comme d'autres l'ont fait remarquer, il est nécessaire d'utiliser un paquetage comme celui-ci car les structures, de par leur nature, ont des tailles inconnues et ne peuvent pas être converties en tableaux d'octets.

J'ai inclus du code et un play .

package main

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

type P struct {
    X, Y, Z int
    Name    string
}

type Q struct {
    X, Y *int32
    Name string
}

func main() {
    // Initialize the encoder and decoder.  Normally enc and dec would be
    // bound to network connections and the encoder and decoder would
    // run in different processes.
    var network bytes.Buffer        // Stand-in for a network connection
    enc := gob.NewEncoder(&network) // Will write to network.
    dec := gob.NewDecoder(&network) // Will read from network.
    // Encode (send) the value.
    err := enc.Encode(P{3, 4, 5, "Pythagoras"})
    if err != nil {
        log.Fatal("encode error:", err)
    }

    // HERE ARE YOUR BYTES!!!!
    fmt.Println(network.Bytes())

    // Decode (receive) the value.
    var q Q
    err = dec.Decode(&q)
    if err != nil {
        log.Fatal("decode error:", err)
    }
    fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
}
11
Adam

Vous devez utiliser un tampon d'octets au lieu d'une chaîne, les autres méthodes suggérées créent un SHA1 de longueur variable, la longueur standard SHA1 doit être de 20 octets (160 bits)

package main

import (
    "crypto/sha1"
    "fmt"
    "encoding/binary"
    "bytes"
)

type myStruct struct {
    ID   string
    Data string
}

func main() {
    var bin_buf bytes.Buffer
    x := myStruct{"1", "Hello"}
    binary.Write(&bin_buf, binary.BigEndian, x)
    fmt.Printf("% x", sha1.Sum(bin_buf.Bytes()))
}

Essayez vous-même: http://play.golang.org/p/8YuM6VIlLV

C'est une méthode très facile et cela fonctionne très bien.

Je sais que ce fil est ancien, mais aucune des réponses n'a été acceptée, et il existe un moyen simple de le faire.

https://play.golang.org/p/TedsY455EBD

code important du terrain de jeu

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

type MyStruct struct {
  Name string `json:"name"`
}

testStruct := MyStruct{"hello world"}
reqBodyBytes := new(bytes.Buffer)
json.NewEncoder(reqBodyBytes).Encode(testStruct)

reqBodyBytes.Bytes() // this is the []byte
6
Cody Jacques

Avez-vous envisagé de le sérialiser en bson? http://labix.org/gobson

2
Erik St. Martin

Jetez un coup d’œil à https://blog.golang.org/go-slices-usage-and-internals Plus précisément, découpez les internes. L'idée est d'imiter la structure interne de slice et de pointer vers notre structure au lieu d'une séquence d'octets

package main

import (
    "fmt"
    "unsafe"
)

// our structure
type A struct {
    Src int32
    Dst int32
    SrcPort uint16
    DstPort uint16
}

// that is how we mimic a slice
type ByteSliceA struct {
    Addr *A
    Len int
    Cap int
}

func main() {
    // structure with some data
    a := A{0x04030201,0x08070605,0x0A09, 0x0C0B}

    // create a slice structure
    sb := &ByteSliceA{&a, 12, 12} // struct is 12 bytes long, e.g. unsafe.Sizeof(a) is 12

    // take a pointer of our slice mimicking struct and cast *[]byte on it:     
    var byteSlice []byte = *(*[]byte)(unsafe.Pointer(sb))

    fmt.Printf("%v\n", byteSlice)
}

Sortie:

[1 2 3 4 5 6 7 8 9 10 11 12]

https://play.golang.org/p/Rh_yrscRDV6

0
Kax