相当于类型继承(通过接口进行gob编码/解码)

时间:2015-02-17 18:15:57

标签: types go polymorphism

我正在尝试编写一个对各种类型的消息进行编码/解码的函数。

在OO语言中,我会使用类型继承,但是Go没有这个概念,ref:http://golang.org/doc/faq#inheritance,所以相反,在这里,我试图使用“marker interface”样式来利用接口继承为此目的而已。

错误来自golang org src / encoding / gob / decode.go:

   line 1019// Common confusing case: local interface type, remote concrete type.

..是的,我发现这令人困惑!!

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

运行此操作

我不能让这个工作,我做错了什么?求救!

更新

(我也试过gob.Register(m1)没有效果)。

我已经研究过类型嵌入,但它没有做我想做的事情,正如你在这个例子中看到的那样(我从jcbwlkr的代码中修改过):https // play .golang .org / p / P6AwVQqQcM(也要注意我可能有几十种/几百种消息类型!)

我很可能正在咆哮错误的树,而且我需要放弃 关于问题的整个想法(但这就是我现在正在尝试做的事情:学习如何“思考一下” vs OO思考。使用类型嵌入可以工作,但我必须创建一个嵌入(组合)其中所有可能类型的主类型:gob使解码成为可能,类型开关让我看到我得到的,但这一切<对于思考,感觉非常可怕和不舒服。

(我习惯于静态和动态语言,所以我对鸭子打字很满意,但是这感觉就像是一个没有任何一端光谱的中途宿舍!)。

所以我在这里要问两件事:

  1. 如何解决这个特殊问题(即了解什么是可能的) 带接口)和
  2. 设计替代品(和类型嵌入是 其中之一,所以感谢突出显示:) :)。
  3. 这里;破碎的代码:

    package main
    
    import (
        "fmt"
        "bytes"
        "log"
        "encoding/gob"
    )
    
    type Msger interface {
        IsMsg()
    }
    
    type ClientMsg struct {
        Id      string
    }
    type ServerMsg struct {
        Id      string
    }
    
    func (m ClientMsg) IsMsg() { }
    func (m ServerMsg) IsMsg() { }
    
    func encode(m Msger) (bb bytes.Buffer) {
        enc := gob.NewEncoder(&bb)
        err := enc.Encode(m)
        if err != nil {
            log.Fatal("Cannot encode! err=", err)
        }
        return
    }
    
    func decode(m Msger, bb bytes.Buffer) {     // for A
    //func decode(m *Msger, bb bytes.Buffer) {  // for B, C
        dec := gob.NewDecoder(&bb)
        err := dec.Decode(&m)
        if err != nil {
            log.Fatal("Cannot decode Msg! err=", err)
        }
        return
    }
    
    func main() {
        m1 := ClientMsg{"id_1"}
        b1 := encode(m1)
        p_bb := bytes.NewBuffer(b1.Bytes())
    
        var mDecoded ClientMsg // for A, B, C
        //var mDecoded interface{} // D: : cannot use mDecoded (type interface {}) as type Msger in argument to decode: interface {} does not implement Msger (missing IsMsg method)
        decode(mDecoded, *p_bb)     // A: gives: Cannot decode Msg! err=gob: local interface type *main.Msger can only be decoded from remote interface type; received concrete type ClientMsg = struct { Id string; }
    
        //decode(mDecoded, *p_bb)  // B: gives: cannot use mDecoded (type ClientMsg) as type *Msger in argument to decode: *Msger is pointer to interface, not interface
        //decode(&mDecoded, *p_bb) // C: gives: cannot use &mDecoded (type *ClientMsg) as type *Msger in argument to decode: *Msger is pointer to interface, not interface
    
        fmt.Printf("m1 Decoded='%v'\n", mDecoded)
    }
    

1 个答案:

答案 0 :(得分:0)

我不是使用标记接口,而是采用Type Embedding的方法,并将编码/解码方法放在Msg类型上。

package main

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

type Msg struct {
    Id string
}

type ClientMsg struct {
    Msg
}
type ServerMsg struct {
    Msg
}

func (m *Msg) encode() (bb bytes.Buffer) {
    enc := gob.NewEncoder(&bb)
    err := enc.Encode(m)
    if err != nil {
        log.Fatal("Cannot encode! err=", err)
    }
    return
}

func (m *Msg) decode(bb *bytes.Buffer) {
    dec := gob.NewDecoder(bb)
    err := dec.Decode(m)
    if err != nil {
        log.Fatal("Cannot decode Msg! err=", err)
    }
    return
}

func main() {
    // Make a message and encode it to a bytes.Buffer
    m1 := &ClientMsg{Msg{"id_1"}}
    b1 := m1.encode()
    p_bb := bytes.NewBuffer(b1.Bytes())

    // Make a new message and decode the bytes.Buffer from the first
    m2 := &ClientMsg{Msg{}}
    m2.decode(p_bb)

    fmt.Printf("m2 Decoded = '%v'\n", m2.Msg.Id)
}

View it on the Playground

您可以使用一些New方法使此代码更好,以生成ClientMsgServerMsg结构。你还需要将encode的回复传递给bytes.NewBuffer还是按原样使用它?