How to serialize slice of fixed length data structure in Go

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

How to serialize slice of fixed length data structure in Go

问题

以下代码生成了panic: binary.Write: invalid type main.test的错误:

type (
	config struct {
		Key uint16
		Val uint16
	}
	test struct {
		Mode uint32
		Data []config
	}
)

func main() {
	t := test{
		Mode: 5,
		Data: []config{
			{1, 2},
			{3, 4},
		},
	}
	var bs bytes.Buffer
	assert(binary.Write(&bs, binary.LittleEndian, t))
}

关键点是:

  1. config 数据结构的长度是固定的,但 test 结构包含一个可变数量的 config 切片。
  2. 我需要与用 C 编写的其他程序进行交互,所以不能使用类似 GOB 的东西。

除了手动操作之外,是否有其他方法可以对这样的数据结构进行二进制编码?

英文:

The following code generates panic: binary.Write: invalid type main.test:

type (
	config struct {
		Key uint16
		Val uint16
	}
	test struct {
		Mode uint32
		Data []config
	}
)

func main() {
	t := test{
		Mode: 5,
		Data: []config{
			{1, 2},
			{3, 4},
		},
	}
	var bs bytes.Buffer
	assert(binary.Write(&bs, binary.LittleEndian, t))
}

The key point is:

  1. length of the config data structure is fixed, but the test structure contains a slice of config, whose number varies.
  2. I need to interact with other program written in C, so cannot use things like GOB.

Is there anyway to binary-encode such data structure, apart from do it manually?

答案1

得分: 3

问题不在于写出一个切片,因为切片是支持的。引用自binary.Write()

> Write将数据的二进制表示写入w。数据必须是固定大小的值或固定大小值的切片,或者是指向这种数据的指针。

问题在于config的大小不是固定的。它的大小不是固定的,因为它包含一个切片类型的字段,而切片的二进制表示不是固定的(取决于其长度)。

因此,虽然支持写入切片值,但不支持写入包含切片的复合类型值(例如结构体),原因如上所述。

你可以将该字段更改为数组类型(例如[2]config),但我假设这对你来说不够。

你可以使用encoding/binary逐个写入字段,这样你就可以写入切片值。

例如:

var bs bytes.Buffer
fmt.Println(binary.Write(&bs, binary.LittleEndian, t.Mode))
fmt.Println(binary.Write(&bs, binary.LittleEndian, t.Data))

这将输出(在Go Playground上尝试):

<nil>
<nil>

曾经有一个提案扩展encoding/binary以支持类似的情况(参见这里),但被拒绝了。encoding/binary适用于简单的情况。

如果你需要更多的灵活性,可以使用encoding/gob(虽然是Go特定的),或者使用encoding/json(被所有语言支持)。

英文:

The problem is not writing out a slice, as slices are supported. Quoting from binary.Write():

> Write writes the binary representation of data into w. Data must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.

The problem is that the size of config is not fixed. It is not fixed because it contains a field of slice type, and the binary representation of the slice is not fixed (depends on its length).

So writing a slice value is supported, writing a value of composite type (e.g. struct) holding a slice is not supported for the above mentioned reason.

You may change the field to an array type (e.g. [2]config) but I assume this isn't sufficient to you.

You may write the fields using encoding/binary individually, in which case you can write a slice value.

For example:

var bs bytes.Buffer
fmt.Println(binary.Write(&bs, binary.LittleEndian, t.Mode))
fmt.Println(binary.Write(&bs, binary.LittleEndian, t.Data))

This will output (try it on the Go Playground):

<nil>
<nil>

There was a proposal to extend encoding/binary to support similar cases (see here), but was rejected. encoding/binary is for simple things.

If you need more flexibility, use encoding/gob (although Go specific), or use encoding/json (supported by all languages).

huangapple
  • 本文由 发表于 2021年11月24日 17:54:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/70093976.html
匿名

发表评论

匿名网友

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

确定