web-dev-qa-db-ja.com

Goでは、どのようにして構造体をバイト配列に変換できますか?

定義した構造体のインスタンスがあり、それをバイトの配列に変換したいと思います。 [] byte(my_struct)を試しましたが、うまくいきませんでした。また、 binary package を指摘されましたが、どの関数を使用するべきか、どのように使用するべきかはわかりません。例をいただければ幸いです。

26
abw333

Cがこれを処理する方法のようなものが欲しいと思います。そのための方法は組み込まれていません。構造体のバイトとの間で独自のシリアル化と逆シリアル化を定義する必要があります。バイナリパッケージは、構造体のフィールドをバイト配列に追加できるバイトにエンコードするのに役立ちますが、構造体のフィールドを保持するバイト配列の長さとオフセットを指定する必要があります。

他のオプションは、エンコーディングパッケージのいずれかを使用することです: http://golang.org/pkg/encoding/ gobやjsonなど。

編集:

あなたのコメントで言うようにハッシュを作成するためにこれが欲しいので、最も簡単なことは次のように[]byte(fmt.Sprintf("%v", struct))を使用することです: http://play.golang.org/p/yY8mSdZ_kf =

22
Jeremy Wall

可能な解決策の1つは"encoding/gob"標準パッケージ。 gobパッケージは、任意の構造体をバイトの配列にエンコードし、その配列をデコードして構造体に戻すことができるエンコーダー/デコーダーを作成します。素晴らしい投稿があります here

他の人が指摘したように、構造体は本質的にサイズが不明であり、バイトの配列に変換できないため、このようなパッケージを使用する必要があります。

いくつかのコードと 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)
}
12
Adam

私はこのスレッドが古いことを知っていますが、答えはどれも受け入れられませんでした。そして、これを行う非常に簡単な方法があります。

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

遊び場からの重要なコード

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
8
Cody Jacques

文字列の代わりにバイトバッファーを使用する必要があります。他の推奨される方法は、可変長のSHA1を作成します。SHA1標準長は20バイト(160ビット)でなければなりません

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()))
}

自分で試してみてください: http://play.golang.org/p/8YuM6VIlLV

それは本当に簡単な方法であり、うまく機能します。

Bsonにシリアル化することを検討しましたか? http://labix.org/gobson

2
Erik St. Martin

https://blog.golang.org/go-slices-usage-and-internals を見てください。具体的には内部をスライスします。アイデアは、スライスの内部構造を模倣し、バイトシーケンスではなく構造体を指すことです。

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)
}

出力:

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

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

1
Kax
package main

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

type myStruct struct {
    ID   [10]byte
    Data [10]byte
}

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()))
}

binary.Writeは、データ型が割り当てられた固定長メモリを持つ構造体を取ります。

0
Asnim P Ansari

シリアル化はおそらく適切な答えです。

しかし、安全でないことに同意し、構造体を実際にバイトとして読み取る必要がある場合、バイト配列メモリ表現に依存する方が、バイトスライス内部構造に依存するよりも少し良いかもしれません。

type Struct struct {
    Src int32
    Dst int32
    SrcPort uint16
    DstPort uint16
}

const sz = int(unsafe.SizeOf(Struct{}))
var asByteSlice []byte = (*(*[sz]byte)(unsafe.Pointer(&struct_value)))[:]

動作し、構造体への読み取り/書き込みビュー、ゼロコピーを提供します。 2つの「安全でない」ことは、それがひどく壊れる可能性があることを十分に示唆するはずです。

0
temoto

Json marshalを使用するだけです。これは非常に簡単な方法です。

newFsConfig := dao.ConfigEntity{EnterpriseId:"testing"}
newFsConfigBytes, _ := json.Marshal(newFsConfig)
0
kose livs