英文:
Go copy bytes into struct fields with reflection
问题
如何迭代遍历字节切片并将其分配给结构体的字段?
type s struct {
f1 []byte
f2 []byte
f3 []byte
}
func S() s {
x := s{}
x.f1 = make([]byte, 4)
x.f2 = make([]byte, 2)
x.f3 = make([]byte, 2)
return x
}
func main() {
data := []byte{83, 117, 110, 83, 0, 1, 0, 65}
Z := S()
// 从这里开始的伪代码
i := 0
fields := []interface{}{&Z.f1, &Z.f2, &Z.f3}
for _, field := range fields {
f := *field.(*[]byte)
copy(f, data[i:i+len(f)])
i += len(f)
}
}
期望结果:
- f1 = [83,117,110,83]
- f2 = [0,1]
- f3 = [0,65]
我以前在C/C++中做过类似的操作,但是我不知道如何在Go中实现。我需要将分配函数设计成通用的,因为我将有多个不同的结构体,其中一些可能在数据流中不存在。
理想情况下,我希望传入初始化的结构体,然后我的代码会迭代结构体字段并填充它们。
英文:
How can I iterate over a byte slice and assign them to the fields of a struct?
type s struct {
f1 []byte
f2 []byte
f3 []byte
}
func S s {
x := s{}
x.f1 = make([]byte, 4)
x.f1 = make([]byte, 2)
x.f1 = make([]byte, 2)
return x
}
func main() {
data := []byte{83, 117, 110, 83, 0, 1, 0, 65}
Z := S()
//pesudo code from here
i:= 0
for field in Z {
field = data[i:len(field)]
i += len(field)
}
Expecting:
- f1 = [83,117,110,83]
- f2 = [0,1]
- f3 = [0,65]
I've done this in C/C++ before but I can't figure out how to do it in Go. I need the assigning function to be generic as I'm going to have several different structs some of which may not exist in the stream.
Ideally I want to pass in the initialized struct and my code would iterate over the struct fields filling them in.
答案1
得分: 1
利用二进制/编码包中的反射代码。
步骤1:将字段声明为数组而不是切片。
type S struct {
F1 [4]byte
F2 [2]byte
F3 [2]byte
}
步骤2:使用binary.Read将数据解码到结构体中。
var s S
data := []byte{83, 117, 110, 83, 0, 1, 0, 65}
err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &s)
if err != nil {
log.Fatal(err)
}
步骤3:完成!
fmt.Print(s) // 输出 {[83 117 110 83] [0 1] [0 65]}
https://go.dev/play/p/H-e8Lusw0RC
英文:
Leverage the reflection code in the binary/encoding package.
Step 1: Declare the fields as arrays instead of slices.
type S struct {
F1 [4]byte
F2 [2]byte
F3 [2]byte
}
Step 2: Decode the data to the struct using binary.Read
var s S
data := []byte{83, 117, 110, 83, 0, 1, 0, 65}
err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &s)
if err != nil {
log.Fatal(err)
}
Step 3: Done!
fmt.Print(s) // prints {[83 117 110 83] [0 1] [0 65]}
答案2
得分: 0
你可以使用reflect.Copy
。与内置的copy
类似,它将数据复制到目标位置,直到达到目标位置的长度。确保你需要设置的字段是可导出的。
func main() {
data := []byte{83, 117, 110, 83, 0, 1, 0, 65}
z := S{
F1: make([]byte, 4),
F2: make([]byte, 2),
F3: make([]byte, 2),
}
SetBytes(&z, data)
fmt.Println(z) // {[83 117 110 83] [0 1] [0 65]}
}
func SetBytes(dst any, data []byte) {
v := reflect.ValueOf(dst)
if v.Kind() != reflect.Ptr {
panic("dst must be addressable")
}
v = v.Elem()
j := 0
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
if field.Kind() != reflect.Slice {
continue
}
j += reflect.Copy(v.Field(i), reflect.ValueOf(data[j:]))
}
}
由于假设data
始终为[]byte
,你可以直接对其进行子切片。
另外,你还可以使用reflect.Value#Slice
:
d := reflect.ValueOf(data)
// 然后在后面
j += reflect.Copy(v.Field(i), d.Slice(j, d.Len()))
Playground: https://go.dev/play/p/o1MR1qrW5pL
英文:
You can use reflect.Copy
. Like the built-in copy
, it copies data into the destination up to its length. Make sure the fields you need to set are exported.
func main() {
data := []byte{83, 117, 110, 83, 0, 1, 0, 65}
z := S{
F1: make([]byte, 4),
F2: make([]byte, 2),
F3: make([]byte, 2),
}
SetBytes(&z, data)
fmt.Println(z) // {[83 117 110 83] [0 1] [0 65]}
}
func SetBytes(dst any, data []byte) {
v := reflect.ValueOf(dst)
if v.Kind() != reflect.Ptr {
panic("dst must be addressable")
}
v = v.Elem()
j := 0
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
if field.Kind() != reflect.Slice {
continue
}
j += reflect.Copy(v.Field(i), reflect.ValueOf(data[j:]))
}
}
Since data
is assumed to be always []byte
, you can subslice it directly.
Alternatively, you can use reflect.Value#Slice
:
d := reflect.ValueOf(data)
// and later
j += reflect.Copy(v.Field(i), d.Slice(j, d.Len()))
Playground: https://go.dev/play/p/o1MR1qrW5pL
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论