golang casting byte array to struct

21,951

Solution 1

According to http://golang.org/pkg/encoding/binary/#Read :

Data must be a pointer to a fixed-size value or a slice of fixed-size values.

So you can't use slice []byte in your structure. But you can use fixed size array for it.
Like this:

package main

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

type T struct {
    A int16
    B int8
    C [256]byte
}

func main() {
    // Create a struct and write it.
    t := T{A: 99, B: 10}
    buf := &bytes.Buffer{}
        
    err := binary.Write(buf, binary.BigEndian, t)
    
    if err != nil {
        panic(err)
    }
    fmt.Println(buf)

    // Read into an empty struct.
    t = T{}
    err = binary.Read(buf, binary.BigEndian, &t)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%d %d", t.A, t.B)
}

Go playground

Solution 2

I think binpacker will be greate to handle this case:

package main

import (
    "bytes"
    "fmt"

    "github.com/zhuangsirui/binpacker"
)

type T struct {
    A uint16
    B string
    C []byte
}

func main() {
    field1 := uint16(1)
    field2 := "Hello World"
    field3 := []byte("Hello World")
    buffer := new(bytes.Buffer)
    binpacker.NewPacker(buffer).
        PushUint16(field1).
        PushUint16(uint16(len(field2))).PushString(field2).
        PushUint16(uint16(len(field3))).PushBytes(field3)

    t := new(T)
    unpacker := binpacker.NewUnpacker(buffer)
    unpacker.FetchUint16(&t.A).StringWithUint16Perfix(&t.B).BytesWithUint16Perfix(&t.C)
    fmt.Println(t)
}
Share:
21,951
user642318
Author by

user642318

Updated on July 05, 2020

Comments

  • user642318
    user642318 almost 4 years

    I am looking for clean way to cast byte array to struct for client-server application. I know most ppl turn to gob package for this solution however I do not control the encoding for the application. that being said, I only programmed the server application not the client, there is a mutual contract for the protocol that is being exchanged.

    The best I could come out is the following.

    type T struct {
        A int16
        B int8
        C []byte
    }
    
    func main() {
        // Create a struct and write it.
        t := T{A: 99, B: 10}
        buf := &bytes.Buffer{}
    
        buf1 := []byte{5, 100, 100}
        fmt.Println(buf1)
    
        buf.Write(buf1)
    
        //err := binary.Write(buf, binary.BigEndian, t)
    
        //if err != nil {
        //  panic(err)
        //}
        fmt.Println(buf)
    
        // Read into an empty struct.
        t = T{}
        err := binary.Read(buf, binary.BigEndian, &t)
        if err != nil {
            panic(err)
        }
        fmt.Printf("%d %d", t.A, t.B)
    }
    

    However, as soon as number bytes does not coincide with the size of the struct, then go will send a panic. How can I modify this to work without the panic if undersize or oversize

    Go playground

  • user642318
    user642318 almost 9 years
    Any idea how to cast to variable size
  • RoninDev
    RoninDev almost 9 years
    Depends on your data structure. You can split your source array onto 2 parts. First part will contains only fixed-size data (A and B in your case 3 bytes). Second part will contains array data. In that way you need to create new structure, without array part, like type T struct { A int16 B int8 }. And decode both parts separately