将struct字段序列化为预先存在的字节切片

时间:2017-12-19 07:13:28

标签: go serialization

我有一个设置,我通过网络接收数据并将其序列化到我的结构。它工作正常,但现在我需要将数据序列化到切片缓冲区以通过网络发送它。

我试图避免分配超过需要的数量,所以我已经设置了一个缓冲区,我喜欢写所有的序列化。但我不确定该怎么做。

我的设置是这样的:

recieveBuffer := make([]byte, 1500)
header := recieveBuffer[0:1]
message := recieveBuffer[1:]

所以我试图将结构中的字段写入message,并将所有字段的总字节数作为header的值。

这就是我对结构反序列化的方式:

// Deserialize ...
func (userSession *UserSession) Deserialize(message []byte) {
    userSession.UID = int64(binary.LittleEndian.Uint32(message[0:4]))
    userSession.UUID = string(message[4:40])
    userSession.Username = string(message[40:])
}
但是,我并不知道如何做到这一点。是否可以在复制到message之前不为每个我要序列化的字段创建缓冲区?

2 个答案:

答案 0 :(得分:1)

给定预分配的缓冲区buf,您可以像这样反转该过程:

buf[0] = byte(40+len(userSession.Username))
binary.LittleEndian.PutUint32(buf[1:], uint32(int32(userSession.UID)))
copy(buf[5:41], userSession.UUID)
copy(buf[41:], userSession.Username)

答案 1 :(得分:0)

给出两个辅助函数。

将基元编码为字节切片的一个:

func EncodeNumber2NetworkOrder(v interface{}) ([]byte, error) {
   switch v.(type) {
   case int: // int is at least 32 bits
       b := make([]byte, 4)
       binary.BigEndian.PutUint32(b, uint32(v.(int)))
       return b, nil
   case int8:
       b := []byte{byte(v.(int8))}
       return b, nil
   // ... truncated

和一个将原始的非字节切片转换为字节切片

func EncodeBigEndian(in []float64) []byte {
   var out []byte = make([]byte, len(in)*8)
   var wg sync.WaitGroup

   wg.Add(len(in))
   for i := 0; i < len(in); i++ {
       go func(out *[]byte, i int, f float64) {
           defer wg.Done()
           binary.BigEndian.PutUint64((*out)[(i<<3):], math.Float64bits(f))
       }(&out, i, in[i])
   }
   wg.Wait()

   return out
}

对于像

这样的虚假结构,你的二进制序列化可能看起来像这样
 type Foo struct {
     time int64
     data []float64
 }

 func Encode(f *Foo) []byte {
    da := encoder.EncodeBigEndian(f.data)
    bytes := make([]byte,0)
    bytes = append(bytes, da...)
    return bytes
 }