英文:
casting overlapping structs in golang
问题
我是你的中文翻译助手,以下是你要翻译的内容:
我刚开始学习golang,试图找出将一块字节转换为正确结构的正确方法。所有结构体都以两个字节开头,这两个字节决定了剩余字节的布局。在C语言中,我会将指针指向内存块的开头,并将其强制转换为一个只包含这两个字节的简单结构体(下面的X),但在这里我得到了一个无效的类型断言。我可能完全错了,希望能得到帮助。
简而言之,我只想在类型Foo
上创建一个自定义方法,这是我想执行类型转换的唯一原因。如果解决方案非常复杂,我想我会创建函数而不是方法。我只是好奇。
英文:
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.
答案1
得分: 1
Go通常会努力避免类似C语言的内存操作,因为这样容易导致内存泄漏、错误行为和安全漏洞,除非采取了非常谨慎的措施和测试。但这并不意味着完全不可能;事实上,恰如其名的unsafe.Pointer
就是为了这个目的而公开的。使用时请谨慎。
英文:
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.
答案2
得分: 1
这是我的解决方案。它涉及到一些不同的技巧:
- 在各个结构体中嵌入共享结构体。
- 使用
encoding/binary
包将字节加载到结构体中。 - 先填充头部结构体的前两个字节,然后根据情况决定创建和填充哪个子类型。
- 对于这种情况,始终使用固定长度的整数类型。
- 字段名称必须是
UpperCase
,才能从encoding/binary
中填充。 - 这种方式管理数据的编组和解组是相当脆弱的,但我相信你已经知道这一点。
这是我的解决方案:
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)
}
}
英文:
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)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论