dongyuji7309 2016-01-26 02:35
浏览 87
已采纳

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

I have been struggling to understand the difference between encoding/decoding an interface type when that type is embedded in a struct, vs. when it's not embedded at all.

Using the following example: here in the playground

Note the code declares an interface IFace. It declares a non-exported struct impl. It sets up a few Gob methods to Register, GobEncode, and GobDecode the impl struct.

Then, it also declares a struct Data which is exported, and has a single field Foo which is of the interface type IFace.

So, there's an interface, a struct which implements it, and a container struct which has a field whose value is that interface type.

My problem is that the container struct Data is happily sent through the Gob gauntlet, and, when it goes through, it happily encodes and decodes the IFace field in the Data struct... great! But, I cannot seem to be able to send just an instance of the IFace value through the gob gauntlet.

What is the magic invocation I am missing?

Searching for the error message gives a number of results, but I believe I have satisfied the Gob contract.... and the "proof" of that is in the successful struct gobbing. Obviously I have missed something, but can't see it.

Note, the output of the program is:

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

The actual code is:

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 impl{val}
}

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 := Data{bilbo}

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

    fmt.Printf("Encoding %v now
", 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
", pdat)

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

}
  • 写回答

1条回答 默认 最新

  • dongling3243 2016-01-26 04:54
    关注

    The call

    err = enc.Encode(baggins)
    

    passes an impl value to Encode. It does not pass a value of type IFace. The document http://research.swtch.com/interfaces may be helpful in understanding why this is. The value is encoded as the concrete type impl.

    If you want to decode to an interface type, then you must encode an interface type. One way to do this is to pass a pointer to the interface value:

    err = enc.Encode(&baggins)
    

    In this call, a *IFace is passed to Encode. After dereferencing the pointer, the encoder sees that the value is an interface type and encodes it as an interface type. Because the gob package does all necessary dereferencing and indirection when converting values, the extra level of indirection on the call to Encode does not require an extra level of indirection when decoding.

    <kbd>playground example</kbd>

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP