gob 解码结构中的接口与原始接口之间的区别

Posted

技术标签:

【中文标题】gob 解码结构中的接口与原始接口之间的区别【英文标题】:Difference between gob decoding an interface in a struct, vs. raw 【发布时间】:2016-01-26 02:35:25 【问题描述】:

我一直在努力理解当接口类型嵌入到结构中时编码/解码接口类型与根本不嵌入时之间的区别。

使用以下示例:here in the playground

注意代码声明了一个接口IFace。它声明了一个非导出结构impl。它为RegisterGobEncodeGobDecodeimpl 结构设置了一些Gob 方法。

然后,它还声明了一个结构体Data,该结构体被导出,并且有一个Foo的字段Foo,它的接口类型为IFace

所以,有一个接口,一个实现它的结构体,以及一个容器结构体,该结构体具有一个字段,其值为该接口类型。

我的问题是容器结构Data 很高兴通过 Gob 手套发送,并且当它通过时,它很高兴对Data 结构中的 IFace 字段进行编码和解码......太好了!但是,我似乎无法通过 gob gauntlet 仅发送 IFace 值的一个实例。

我缺少的魔法调用是什么?

搜索错误消息给出了许多结果,但我相信我已经满足了 Gob 合同......并且“证明”就是成功的 struct gobbing。显然我错过了一些东西,但看不到它。

注意,程序的输出是:

Encoding IFace:bilbo now
Encoding IFace:baggins now
Decoded IFace:bilbo now
decode error: gob: local interface type *main.IFace can only be decoded from remote interface type; received concrete type impl
Decoded <nil> now

实际代码是:

package main

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

type IFace interface 
    FooBar() string


type impl struct 
    value string


func init() 
    gob.Register(impl)


func (i impl) FooBar() string 
    return i.value


func (i impl) String() string 
    return "IFace:" + i.value


func (i impl) GobEncode() ([]byte, error) 
    return []byte(i.value), nil


func (i *impl) GobDecode(dat []byte) error 
    val := string(dat)
    i.value = val
    return nil


func newIFace(val string) IFace 
    return implval


type Data struct 
    Foo IFace


func main() 

    var network bytes.Buffer        // Stand-in for a network connection
    enc := gob.NewEncoder(&network) // Will write to network.
    dec := gob.NewDecoder(&network) // Will read from network.

    var err error

    var bilbo IFace
    bilbo = newIFace("bilbo")

    var baggins IFace
    baggins = newIFace("baggins")

    dat := Databilbo

    fmt.Printf("Encoding %v now\n", dat)
    err = enc.Encode(dat)
    if err != nil 
        fmt.Println("encode error:", err)
    

    fmt.Printf("Encoding %v now\n", baggins)
    err = enc.Encode(baggins)
    if err != nil 
        fmt.Println("encode error:", err)
    

    var pdat Data
    err = dec.Decode(&pdat)
    if err != nil 
        fmt.Println("decode error:", err)
    
    fmt.Printf("Decoded %v now\n", pdat)

    var pbag IFace
    err = dec.Decode(&pbag)
    if err != nil 
        fmt.Println("decode error:", err)
    
    fmt.Printf("Decoded %v now\n", pbag)


【问题讨论】:

***.com/questions/32428797/… @JiangYD - Unmarshal 方法适用于encoding/jsonencoding/gob 是否有等价物? golang.org/pkg/encoding/gob/#GobDecoder 好的,@JiangYD - 我在问题中的代码是使用 GobDecoder 和 GobEncoder (当接口嵌入到结构中时它可以工作,但当接口是独立的时不能工作)。 这并没有破坏the reflector knows the underlying type 的问题。将接口更改为结构,并将动态类型嵌入到该结构中。 【参考方案1】:

电话

err = enc.Encode(baggins)

impl 值传递给Encode。它不传递IFace 类型的值。文档http://research.swtch.com/interfaces 可能有助于理解为什么会这样。该值被编码为具体类型impl

如果要解码为接口类型,则必须对接口类型进行编码。一种方法是传递一个指向接口值的指针:

err = enc.Encode(&baggins)

在此调用中,*IFace 被传递给 Encode。解引用指针后,编码器看到该值是接口类型,并将其编码为接口类型。因为 gob 包在转换值时会执行所有必要的取消引用和间接操作,所以对 Encode 调用的额外间接级别在解码时不需要额外的间接级别。

playground example

【讨论】:

因此,在对“原始”接口“实例”进行编码时,变量前面的简单&amp; 是神奇的,我也非常感谢该接口文档的链接,仍在阅读它。我将声明在编码为“挑剔”时对接口进行双重取消引用的要求,尤其是在解码时而非编码时看到问题的症状时。我想如果我查看实际的编码流,我应该会看到差异。

以上是关于gob 解码结构中的接口与原始接口之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

golang 显示无法将数据附加到gob文件 - 当尝试解码写入的数据时,解码器将使用“缓冲区中的额外数据”错误输出

GoLang读写数据---下

dubbo与http接口区别

gob:类型不匹配:没有匹配的字段编译解码器 - Golang

WebRTC模块化设计思想之编解码

WebRTC模块化设计思想之编解码