6

我有一个带有未导出字段的结构,应该对其进行 gob 编码和解码。

说:

type A struct {
    s int
}
func (a *A) Inc() {
    a.s++
}

显然在那种情况下我需要实现gob.GobEncodergob.GobDecoder接口。如果我直接使用结构,一切正常

https://play.golang.org/p/dm3HwaI8eU

但我还需要一个实现相同逻辑且可序列化的接口:

type Incer interface {
    gob.GobEncoder
    gob.GobDecoder
    Inc()
}

完整代码: https: //play.golang.org/p/Zig2mPrnrq

突然它惊慌失措:

panic: interface conversion: interface is nil, not gob.GobDecoder [recovered]
    panic: interface conversion: interface is nil, not gob.GobDecoder

但是,如果我将 gob 接口注释掉,一切都会再次恢复正常。

我错过了什么重要的东西吗?因为所描述的行为对我来说似乎很奇怪

4

2 回答 2

3

问题在于Incer接口实现了一个特殊的接口,对encoding/gob包来说是特殊的:gob.GobDecoder.

如果您的Incer接口仅包含该Inc()方法,它将起作用,因为 gob 解码器看到您正在解码为接口类型,并且它将使用传输的类型来解码该值并在运行时检查解码的值是否(包含其类型和在流中传输)实现目标接口类型,在这种情况下它将:

type Incer interface {
    Inc()
}

所以解码成功。

如果Incer接口还嵌入了gob.GobEncodergob.GobDecoder接口,则根据定义,它们负责进行编码/解码。如果一个类型实现了这些接口,解码器将不会尝试使用传输的类型解码值,而是调用GobDecode()目标值的方法,如果需要,创建一个零值。

由于您将nil值传递给Decoder.Decode(),解码器需要创建一个零值,但它不知道要实例化什么类型,因为您传递的值是指向接口的指针。您不能创建接口类型的值,只能创建可能满足某些接口的具体类型的值。

您不能在界面中包含gob.GobEncoder和。我知道你想确保实现确实实现了它们,但是——正如你所看到的——你将无法将它们解码为“通用”接口值。此外,我什至不认为有必要将它们包含在:中,并且不是使它们可传输的唯一方法,还有包检查它们。gob.GobDecoderIncerIncerIncergob.GobEncodergob.GobDecoderencoding.BinaryMarshalerencoding.BinaryUnmarshalerencoding/gob

于 2017-04-10T14:42:47.510 回答
1

在您的情况下,您需要定义您期望解码转储到接口值的内存“布局”是什么。当你声明

var v Incer

您没有向解码器提供有关必须如何进行解码的任何线索。如果您对解码器说您希望解码 main.A 结构,它可以使用您定义的方法(*A).GobEncode()(*A).GobDecode()

var v Incer
v = &A{}

游乐场链接: https: //play.golang.org/p/WUNRKGTVIS

这是gob 文档中提供的示例

于 2017-04-10T14:32:11.777 回答