简体   繁体   English

在 Go 中,如何将结构转换为字节数组?

[英]In Go, how can I convert a struct to a byte array?

I have an instance of a struct that I defined and I would like to convert it to an array of bytes.我有一个我定义的结构实例,我想将它转换为一个字节数组。 I tried []byte(my_struct), but that did not work.我试过 []byte(my_struct),但没有用。 Also, I was pointed to the binary package , but I am not sure which function I should use and how I should use it.另外,我被指向了二进制文件 package ,但我不确定我应该使用哪个 function 以及我应该如何使用它。 An example would be greatly appreciated.一个例子将不胜感激。

One possible solution is the "encoding/gob" standard package.一种可能的解决方案是"encoding/gob"标准包。 The gob package creates an encoder/decoder that can encode any struct into an array of bytes and then decode that array back into a struct. gob 包创建了一个编码器/解码器,可以将任何结构编码为字节数组,然后将该数组解码回结构。 There's a great post, here .有一个很棒的帖子,在这里

As others have pointed out, it's necessary to use a package like this because structs, by their nature, have unknown sizes and cannot be converted into arrays of bytes.正如其他人指出的那样,有必要使用这样的包,因为结构本质上具有未知的大小并且无法转换为字节数组。

I've included some code and a play .我已经包含了一些代码和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)
}

I assume you want something like the way C handles this.我假设你想要像 C 处理这个的方式。 There is no built in way to do that.没有内置的方法可以做到这一点。 You will have to define your own serialization and deserialization to and from bytes for your struct.您必须为结构定义自己的字节序列化和反序列化。 The binary package will help you encode the fields in your struct to bytes that you can add to the byte array but you will be responsible for specifying the lengths and offsets in the byte array that will hold the fields from your struct.二进制包将帮助您将结构中的字段编码为可以添加到字节数组的字节,但您将负责指定字节数组中的长度和偏移量,以保存结构中的字段。

Your other options are to use one of the encoding packages: http://golang.org/pkg/encoding/ such as gob or json.您的其他选择是使用编码包之一: http : //golang.org/pkg/encoding/,例如 gob 或 json。

EDIT:编辑:

Since you want this for making a hash as you say in your comment the easisest thing to do is use []byte(fmt.Sprintf("%v", struct)) like so: http://play.golang.org/p/yY8mSdZ_kf由于您希望按照您在评论中所说的那样制作散列,因此最简单的方法是使用[]byte(fmt.Sprintf("%v", struct))像这样: http : []byte(fmt.Sprintf("%v", struct)) p/yY8mSdZ_kf

I know this thread is old, but none of the answers were accepted, and there's a pretty simple way to do this.我知道这个线程很旧,但是没有一个答案被接受,并且有一种非常简单的方法可以做到这一点。

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

important code from playground操场上的重要代码

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

Just use json marshal, this is a very simple way.使用json marshal,这是一个非常简单的方法。

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

Serialization is likely proper answer.序列化可能是正确的答案。

But if you consent to unsafety and actually need to read struct as bytes, then relying on byte array memory representation might be a bit better than relying on byte slice internal structure.但是,如果您同意不安全并且实际上需要将 struct 作为字节读取,那么依赖字节数组内存表示可能比依赖字节切片内部结构要好一些。

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)))[:]

Works and provides read-write view into struct, zero-copy.工作并提供对结构的读写视图,零拷贝。 Two "unsafe" should hint enough that it may break badly.两个“不安全”应该足以暗示它可能会严重损坏。

You should use a bytes buffer instead of a string, the other suggested methods create a SHA1 of variable length, the SHA1 standard length must be 20 bytes (160 bits)您应该使用字节缓冲区而不是字符串,其他建议的方法创建可变长度的 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()))
}

Try it yourself: http://play.golang.org/p/8YuM6VIlLV自己试试: http : //play.golang.org/p/8YuM6VIlLV

It's a really easy method and it works great.这是一个非常简单的方法,而且效果很好。

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 takes a struct which has fixed length memory allocated datatype. binary.Write 采用具有固定长度内存分配数据类型的结构。

json.Marshal is the best option to convert a struct to []byte, see example below: json.Marshal 是将结构体转换为 []byte 的最佳选择,请参见下面的示例:

package main

import (
    "encoding/json"
    "fmt"
)

type ExampleConvertToByteArray struct {
    Name    string
    SurName string
}

func main() {

    example := ExampleConvertToByteArray{
        Name:    "James",
        SurName: "Camara",
    }
    
    var exampleBytes []byte
    var err error

    exampleBytes, err = json.Marshal(example)
    if err != nil {
        print(err)
        return
    }

    fmt.Println(string(exampleBytes))
}

Go playground -> https://play.golang.org/p/mnB9Cxy-2H3去游乐场 -> https://play.golang.org/p/mnB9Cxy-2H3

Take a look at https://blog.golang.org/go-slices-usage-and-internals Specifically slice internals.看看https://blog.golang.org/go-slices-usage-and-internals具体切片内部。 The idea is to mimic slice's internal structure and point to our struct instead of a byte sequence:这个想法是模仿切片的内部结构并指向我们的结构而不是字节序列:

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

Output:输出:

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

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

Have you considered serializing it to bson?你有没有考虑将它序列化到bson? http://labix.org/gobson http://labix.org/gobson

var v any
b := (*[unsafe.Sizeof(v)]byte)(unsafe.Pointer(&v))
c := b[:]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM