【问题标题】:Go equivalent of type inheritace (gob encode/decode via interfaces)Go 等价于类型继承(通过接口进行 gob 编码/解码)
【发布时间】:2015-04-18 13:10:10
【问题描述】:

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

在 OO 语言中,我会使用类型继承,但 Go 没有这个概念,参考:http://golang.org/doc/faq#inheritance,因此,我尝试使用“标记接口”样式来为此利用接口继承目的。

错误来自 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(还要注意我可能有数十/数百种消息类型!)

很可能我找错了树,我需要放弃如何我正在考虑这个问题的整个想法(但这就是我目前正在尝试做的事情:学习如何“在 Go 中思考” vs OO 思考)。使用类型嵌入会起作用,但我必须创建一个主类型,在其中嵌入(组合)所有可能的类型:gob 使解码成为可能,类型切换让我看到我得到了什么,但这一切 感觉想想相当可怕和不舒服。

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

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

  1. 如何解决此特定问题(即了解可能发生的情况 带接口),以及
  2. 设计备选方案(类型嵌入是 其中之一,非常感谢您强调这一点):)。

这是损坏的代码:

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)
}

【问题讨论】:

标签: types go polymorphism


【解决方案1】:

我不会使用标记接口,而是使用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 还是可以按原样使用它?

【讨论】:

  • 嗨 jcbwlkr - 感谢您的反馈,我已经研究了类型嵌入,但它并没有做我想做的事情,正如你在这个例子中看到的那样(我已从您的代码中修改):play.golang.org/p/P6AwVQqQcM
  • @SigridHaughty 我明白你的意思。我觉得这里有一个解决方案,但我还没有看到它。祝你好运!
猜你喜欢
  • 2012-12-16
  • 1970-01-01
  • 2021-06-14
  • 2020-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多