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

分享于2022年07月17日 go gob 问答
【问题标题】:Golang Gob解码不解码[]byte数组[重复](Golang Gob decoding does not decode array of []byte [duplicate])
【发布时间】:2022-02-23 20:44:05
【问题描述】:

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

// 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 结构的解码数据字段长度为零时。


【解决方案1】:

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

chan 或 func 类型的结构字段被完全视为未导出的字段并被忽略。

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

可以导出标识符以允许从另一个包访问它。如果两者都导出一个标识符:

  • 标识符名称的第一个字符是 Unicode 大写字母(Unicode 类“Lu”);和
  • 标识符在包块中声明或者是字段名或方法名。

不导出所有其他标识符。

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

Gob 可以按照优先顺序调用相应的方法,对实现 GobEncoder 或 encoding.BinaryMarshaler 接口的任何类型的值进行编码。

Internally ,gob 包依赖于 reflect 包,该包旨在尊重可见性原则。因此 gob 包不会自动处理这些字段,它需要您编写专门的实现。


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

GobEncoder 是描述数据的接口,它为传输到 GobDecoder 的编码值提供自己的表示。实现 GobEncoder 和 GobDecoder 的类型可以完全控制其数据的表示,因此可能包含私有字段、通道和函数等通常无法在 gob 流中传输的内容。

例子

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)

}

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

  • 感谢您的回答,原来这是一个可见性问题。没有正确阅读文档我的错