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

huangapple go评论96阅读模式
英文:

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

问题

我有一个我定义的结构体的实例,我想将它转换为字节数组。我尝试了[]byte(my_struct),但没有成功。我也被指向了binary包,但我不确定应该使用哪个函数以及如何使用它。如果有一个示例,将不胜感激。

英文:

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. Also, I was pointed to the <a href="http://golang.org/pkg/encoding/binary/">binary package</a>, but I am not sure which function I should use and how I should use it. An example would be greatly appreciated.

答案1

得分: 49

一个可能的解决方案是使用"encoding/gob"标准包。gob包创建了一个可以将任何结构体编码为字节数组,然后将该数组解码回结构体的编码器/解码器。这里有一篇很棒的文章链接

正如其他人指出的那样,使用这样的包是必要的,因为结构体本质上具有未知的大小,不能转换为字节数组。

我已经包含了一些代码和一个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() {
    // 初始化编码器和解码器。通常,enc和dec将绑定到网络连接,并且编码器和解码器将在不同的进程中运行。
    var network bytes.Buffer        // 用于模拟网络连接
    enc := gob.NewEncoder(&network) // 将写入网络
    dec := gob.NewDecoder(&network) // 将从网络读取
    // 编码(发送)值。
    err := enc.Encode(P{3, 4, 5, "勾股定理"})
    if err != nil {
        log.Fatal("编码错误:", err)
    }

    // 这里是你的字节数组!!!
    fmt.Println(network.Bytes())

    // 解码(接收)值。
    var q Q
    err = dec.Decode(&q)
    if err != nil {
        log.Fatal("解码错误:", err)
    }
    fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
}
英文:

One possible solution is the &quot;encoding/gob&quot; standard package. 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. 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.

package main

import (
    &quot;bytes&quot;
    &quot;encoding/gob&quot;
    &quot;fmt&quot;
    &quot;log&quot;
)

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(&amp;network) // Will write to network.
    dec := gob.NewDecoder(&amp;network) // Will read from network.
    // Encode (send) the value.
    err := enc.Encode(P{3, 4, 5, &quot;Pythagoras&quot;})
    if err != nil {
        log.Fatal(&quot;encode error:&quot;, err)
    }

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

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

答案2

得分: 40

我假设你想要类似C语言处理这个的方式。Go语言没有内置的方法来实现这个。你需要自己定义序列化和反序列化的方法,将结构体转换为字节流,然后再从字节流中还原出结构体。binary包可以帮助你将结构体的字段编码为字节流,然后你需要自己指定字节流中字段的长度和偏移量。

另外的选择是使用其中一个编码包,比如gob或json:http://golang.org/pkg/encoding/。

编辑:

根据你在评论中提到的要生成哈希值,最简单的方法是使用[]byte(fmt.Sprintf("%v", struct)),示例代码如下:http://play.golang.org/p/yY8mSdZ_kf

英文:

I assume you want something like the way C handles this. 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.

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(&quot;%v&quot;, struct)) like so: http://play.golang.org/p/yY8mSdZ_kf

答案3

得分: 32

只需使用json.Marshal,这是一种非常简单的方法。

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

英文:

Just use json marshal, this is a very simple way.

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

答案4

得分: 27

我知道这个线程很旧,但是没有一个答案被接受,而且有一种非常简单的方法来做到这一点。

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

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() // 这是 []byte
英文:

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

important code from playground

import (
  &quot;bytes&quot;
  &quot;fmt&quot;
  &quot;encoding/json&quot;
)

type MyStruct struct {
  Name string `json:&quot;name&quot;`
}

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

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

答案5

得分: 18

序列化可能是正确的答案。

但是,如果您同意不安全操作并且实际上需要将结构体读取为字节,则依赖于字节数组的内存表示可能比依赖于字节切片的内部结构更好一些。

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

这样可以提供对结构体的读写视图,零拷贝。两个"unsafe"应该足够暗示它可能会出现严重问题。

英文:

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.

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

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

Works and provides read-write view into struct, zero-copy. Two "unsafe" should hint enough that it may break badly.

答案6

得分: 10

你应该使用字节缓冲区而不是字符串,其他建议的方法会创建一个可变长度的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

这是一个非常简单的方法,而且效果很好。

英文:

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)

package main

import (
    &quot;crypto/sha1&quot;
    &quot;fmt&quot;
    &quot;encoding/binary&quot;
    &quot;bytes&quot;
)

type myStruct struct {
    ID   string
    Data string
}

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

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

It's a really easy method and it works great.

答案7

得分: 9

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函数接受一个具有固定长度内存分配数据类型的结构体。

英文:
package main

import (
    &quot;crypto/sha1&quot;
    &quot;fmt&quot;
    &quot;encoding/binary&quot;
    &quot;bytes&quot;
)

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

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

binary.Write takes a struct which has fixed length memory allocated datatype.

答案8

得分: 9

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

英文:

json.Marshal is the best option to convert a struct to []byte, see example below:

package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
)

type ExampleConvertToByteArray struct {
	Name    string
	SurName string
}

func main() {

	example := ExampleConvertToByteArray{
		Name:    &quot;James&quot;,
		SurName: &quot;Camara&quot;,
	}
	
	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

答案9

得分: 3

请看 https://blog.golang.org/go-slices-usage-and-internals
具体来说是切片的内部结构。思路是模拟切片的内部结构,并将其指向我们的结构体,而不是字节序列:

package main

import (
	"fmt"
	"unsafe"
)

// 我们的结构体
type A struct {
	Src     int32
	Dst     int32
	SrcPort uint16
	DstPort uint16
}

// 这就是我们模拟切片的方式
type ByteSliceA struct {
	Addr *A
	Len  int
	Cap  int
}

func main() {
	// 一些数据的结构体
	a := A{0x04030201, 0x08070605, 0x0A09, 0x0C0B}

	// 创建一个切片结构体
	sb := &ByteSliceA{&a, 12, 12} // 结构体长度为12字节,例如 unsafe.Sizeof(a) 是12

	// 获取我们模拟的切片结构体的指针,并将其强制转换为 *[]byte:
	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

英文:

Take a look at https://blog.golang.org/go-slices-usage-and-internals
Specifically slice internals. The idea is to mimic slice's internal structure and point to our struct instead of a byte sequence:

package main

import (
    &quot;fmt&quot;
    &quot;unsafe&quot;
)

// 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 := &amp;ByteSliceA{&amp;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(&quot;%v\n&quot;, byteSlice)
}

Output:

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

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

答案10

得分: 2

你是否考虑将其序列化为bson格式?http://labix.org/gobson

英文:

Have you considered serializing it to bson? http://labix.org/gobson

答案11

得分: 0

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

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

huangapple
  • 本文由 发表于 2013年5月2日 12:46:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/16330490.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定