Golang Gob 解码不解码 []byte 数组

Golang Gob decoding does not decode array of []byte

我正在尝试解码 Inv 结构,但解码相同的编码值 returns 不同的值。

// inv struct
type Inv struct {
    AddrFrom string
    Type     int
    data     [][]byte  
}


inv := Inv{
    AddrFrom: nodeAddress,
    Type:     kind,
    data:     inventories,
}
data := GobEncode(inv)
var payload Inv
gob.NewDecoder(bytes.NewBuffer(data)).Decode(&payload)

这里payload和inv有不同的值。当 inv 结构的解码数据字段长度为零时。

https://pkg.go.dev/encoding/gob

A struct field of chan or func type is treated exactly like an unexported field and is ignored.

https://go.dev/ref/spec#Exported_identifiers

An identifier may be exported to permit access to it from another package. An identifier is exported if both:

  • the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and
  • the identifier is declared in the package block or it is a field name or method name.

All other identifiers are not exported.

https://pkg.go.dev/encoding/gob#hdr-Types_and_Values

Gob can encode a value of any type implementing the GobEncoder or encoding.BinaryMarshaler interfaces by calling the corresponding method, in that order of preference.

Internally, the gob package relies on the reflect包,其设计尊重可见性原则。因此 gob 包不会自动处理这些字段,它需要您编写专门的实现。


https://pkg.go.dev/encoding/gob#GobEncoder

GobEncoder is the interface describing data that provides its own representation for encoding values for transmission to a GobDecoder. A type that implements GobEncoder and GobDecoder has complete control over the representation of its data and may therefore contain things such as private fields, channels, and functions, which are not usually transmissible in gob streams.

例子

package main

import (
    "bytes"
    "encoding/gob"
    "fmt"
    "log"
)

// The Vector type has unexported fields, which the package cannot access.
// We therefore write a BinaryMarshal/BinaryUnmarshal method pair to allow us
// to send and receive the type with the gob package. These interfaces are
// defined in the "encoding" package.
// We could equivalently use the locally defined GobEncode/GobDecoder
// interfaces.
type Vector struct {
    x, y, z int
}

func (v Vector) MarshalBinary() ([]byte, error) {
    // A simple encoding: plain text.
    var b bytes.Buffer
    fmt.Fprintln(&b, v.x, v.y, v.z)
    return b.Bytes(), nil
}

// UnmarshalBinary modifies the receiver so it must take a pointer receiver.
func (v *Vector) UnmarshalBinary(data []byte) error {
    // A simple encoding: plain text.
    b := bytes.NewBuffer(data)
    _, err := fmt.Fscanln(b, &v.x, &v.y, &v.z)
    return err
}

// This example transmits a value that implements the custom encoding and decoding methods.
func main() {
    var network bytes.Buffer // Stand-in for the network.

    // Create an encoder and send a value.
    enc := gob.NewEncoder(&network)
    err := enc.Encode(Vector{3, 4, 5})
    if err != nil {
        log.Fatal("encode:", err)
    }

    // Create a decoder and receive a value.
    dec := gob.NewDecoder(&network)
    var v Vector
    err = dec.Decode(&v)
    if err != nil {
        log.Fatal("decode:", err)
    }
    fmt.Println(v)

}

由于字段类型已经是一个字节切片,您实际上只是遇到了可见性访问问题和专用的所需编组实现,虽然有争议,因为您也可以导出该字段,但应该很简单。