'casting overlapping structs in golang
I'm new to golang and trying to figure out the correct way of casting a block of bytes to the correct struct. All structs start with two bytes that dictate the layout of the remaining bytes. In C I would point to the beginning of the block of memory and cast it as a simple struct that only contained those two bytes (X below) but here I get an invalid type assertion. I'm probably way off base here any help you be appreciated.
package main
import (
"fmt"
)
type A struct {
tag byte
ver byte
data1 int
data2 int
data3 int
}
type B struct {
tag byte
ver byte
data1 float32
}
type X struct {
tag byte
ver byte
}
func main() {
var a A
a.tag = 1
a.ver = 1
x := a.(X)
fmt.Printf("%d,%d", x.tag, x.ver)
}
Edit
In short I just want to create a custom method on type Foo
that is the only reason why I want to perform the cast. If the solutions are very complex I will just create functions instead of methods I guess. I was just curios.
Solution 1:[1]
Here's my solution. It involves a few different tips:
- Embed the shared struct in the individual structs.
- Use
encoding/binary
package to load bytes into structs. - Fill header struct with first two bytes, then make a decision on which subtype to make and fill.
- Always use fixed length int types for this kind of thing.
- Your field names must be
UpperCase
to be fillable fromencoding/binary
- This is a pretty brittle way to manage marshalling.unmarshalling of data, but I'm sure you know that.
Here's my solution:
package main
import (
"bytes"
"encoding/binary"
"fmt"
"log"
)
type A struct {
X
Data1 int32
Data2 int32
Data3 int32
}
type B struct {
X
Data1 int32
}
type X struct {
Tag byte
Ver byte
}
func main() {
var err error
data := []byte{1, 1, 0, 0, 0, 42}
hdr := X{}
err = binary.Read(bytes.NewReader(data[:2]), binary.BigEndian, &hdr)
if err != nil {
log.Fatal(err)
}
fmt.Println(hdr.Tag, hdr.Ver)
if hdr.Tag == 1 {
b := B{}
err = binary.Read(bytes.NewReader(data), binary.BigEndian, &b)
if err != nil {
log.Fatal(err)
}
fmt.Println(b.Data1)
}
}
Solution 2:[2]
Go generally tries to discourage C-like memory fiddling as it leads to memory leaks, incorrect behavior, and security vulnerabilities unless extraordinary caution and testing are applied. That doesn't mean it's impossible though; in fact, the aptly-named unsafe.Pointer
is exposed for exactly this purpose. Use it with caution.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | captncraig |
Solution 2 | Adrian |