如何在不使用反射的情况下将结构体转储到字节数组中?

huangapple go评论92阅读模式
英文:

How do I dump the struct into the byte array without reflection?

问题

我已经找到了encoding/binary包来处理这个问题,但它依赖于reflect包,所以它不能处理未大写(即未导出)的结构字段。然而,尽管我花了一周的时间找出了这个问题,但我仍然有一个问题:如果结构字段不应该被导出,那么如何将它们轻松地转换为二进制数据呢?

**编辑:**这里是一个示例。如果将Data结构的字段名称大写,那么它可以正常工作。但是Data结构被设计为一个抽象类型,所以我不想导出这些字段。

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

type Data struct {
    id int32
    name [16]byte
}

func main() {
    d := Data{Id: 1}
    copy(d.Name[:], []byte("tree"))
    buffer := new(bytes.Buffer)
    binary.Write(buffer, binary.LittleEndian, d)
    // d was written properly
    fmt.Println(buffer.Bytes())
    // try to read...
    buffer = bytes.NewBuffer(buffer.Bytes())
    var e = new(Data)
    err := binary.Read(buffer, binary.LittleEndian, e)
    fmt.Println(e, err)
}
英文:

I already found encoding/binary package to deal with it, but it depended on reflect package so it didn't work with uncapitalized(that is, unexported) struct fields. However I spent a week to find that problem out, I still have a question: if struct fields should not be exported, how do I dump them easily into binary data?

EDIT: Here's the example. If you capitalize the name of fields of Data struct, that works properly. But Data struct was intended to be an abstract type, so I don't want to export these fields.

<!-- language: lang-go -->

package main
import (
    &quot;fmt&quot;
    &quot;encoding/binary&quot;
    &quot;bytes&quot;
)

type Data struct {
    id int32
    name [16]byte
}


func main() {
    d := Data{Id: 1}
    copy(d.Name[:], []byte(&quot;tree&quot;))
    buffer := new(bytes.Buffer)
    binary.Write(buffer, binary.LittleEndian, d)
    // d was written properly
    fmt.Println(buffer.Bytes())
    // try to read...
    buffer = bytes.NewBuffer(buffer.Bytes())
    var e = new(Data)
    err := binary.Read(buffer, binary.LittleEndian, e)
    fmt.Println(e, err)
}

答案1

得分: 35

你最好的选择可能是使用gob包,并让你的结构体实现GobDecoderGobEncoder接口,以便对私有字段进行序列化和反序列化。

这样做是安全的、与平台无关的和高效的。而且你只需要在具有未导出字段的结构体上添加这些GobEncode和GobDecode函数,这意味着你不会在代码的其他部分添加冗余代码。

func (d *Data) GobEncode() ([]byte, error) {
    w := new(bytes.Buffer)
    encoder := gob.NewEncoder(w)
    err := encoder.Encode(d.id)
    if err != nil {
        return nil, err
    }
    err = encoder.Encode(d.name)
    if err != nil {
        return nil, err
    }
    return w.Bytes(), nil
}

func (d *Data) GobDecode(buf []byte) error {
    r := bytes.NewBuffer(buf)
    decoder := gob.NewDecoder(r)
    err := decoder.Decode(&d.id)
    if err != nil {
        return err
    }
    return decoder.Decode(&d.name)
}

func main() {
    d := Data{id: 7}
    copy(d.name[:], []byte("tree"))
    buffer := new(bytes.Buffer)
    // writing
    enc := gob.NewEncoder(buffer)
    err := enc.Encode(d)
    if err != nil {
        log.Fatal("encode error:", err)
    }
    // reading
    buffer = bytes.NewBuffer(buffer.Bytes())
    e := new(Data)
    dec := gob.NewDecoder(buffer)
    err = dec.Decode(e)
    fmt.Println(e, err)
}
英文:

Your best option would probably be to use the gob package and let your struct implement the GobDecoder and GobEncoder interfaces in order to serialize and deserialize private fields.

This would be safe, platform independent, and efficient. And you have to add those GobEncode and GobDecode functions only on structs with unexported fields, which means you don't clutter the rest of your code.

func (d *Data) GobEncode() ([]byte, error) {
	w := new(bytes.Buffer)
	encoder := gob.NewEncoder(w)
	err := encoder.Encode(d.id)
	if err!=nil {
		return nil, err
	}
	err = encoder.Encode(d.name)
	if err!=nil {
		return nil, err
	}
	return w.Bytes(), nil
}

func (d *Data) GobDecode(buf []byte) error {
	r := bytes.NewBuffer(buf)
	decoder := gob.NewDecoder(r)
	err := decoder.Decode(&amp;d.id)
	if err!=nil {
		return err
	}
	return decoder.Decode(&amp;d.name)
}

func main() {
    d := Data{id: 7}
    copy(d.name[:], []byte(&quot;tree&quot;))
    buffer := new(bytes.Buffer)
    // writing
    enc := gob.NewEncoder(buffer)
	err := enc.Encode(d)
    if err != nil {
        log.Fatal(&quot;encode error:&quot;, err)
    }
    // reading
    buffer = bytes.NewBuffer(buffer.Bytes())
    e := new(Data)
    dec := gob.NewDecoder(buffer)
    err = dec.Decode(e)
    fmt.Println(e, err)
}

huangapple
  • 本文由 发表于 2012年10月12日 15:20:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/12854125.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定