go - 尝试使用 go 接口(interface)实现多态性

标签 go go-interface libchan

我正在尝试在第三方库之上创建一个层,在本例中为 libchan .这是我定义的接口(interface):

type ReceiverStream interface {
    Receive(msg interface{}) error
}

type InboundTransport interface {
    WaitReceiveChannel() (ReceiverStream, error)
}

InboundTransportTransport 类型的替代:

// libchan.go
type Transport interface {
    // NewSendChannel creates and returns a new send channel.  The receive
    // end will get picked up on the remote end of the transport through
    // the remote calling WaitReceiveChannel.
    NewSendChannel() (Sender, error)

    // WaitReceiveChannel waits for a new channel be created by the
    // remote end of the transport calling NewSendChannel.
    WaitReceiveChannel() (Receiver, error)
}

只是为了上下文,这是 libchan.Receiver 定义(请注意它匹配我的 ReceiverStream:

// libchan.go
type Receiver interface {
    // Receive receives a message sent across the channel from
    // a sender on the other side of the underlying transport.
    // Receive is expected to receive the same object that was
    // sent by the Sender, any differences between the
    // receive and send type should be handled carefully.  It is
    // up to the application to determine type compatibility, if
    // the receive object is incompatible, Receiver will
    // throw an error.
    Receive(message interface{}) error
}

Transport 由 libchan 库返回 here :

// libchan/session.go:62
func NewTransport(provider StreamProvider) libchan.Transport {
...
}

由于 libchan.TransportInboundTransport 共享一个 WaitReceiveChannel() (ReceiverStream, error) 方法,我想我应该能够子一个为另一个,像这样:

func (ln SpdyListener) Accept(addr string) InboundTransport {
    var listener net.Listener
    var err error
    listener, err = net.Listen("tcp", addr)
    if err != nil {
        log.Fatal(err)
    }
    c, err := listener.Accept()
    if err != nil {
        log.Fatal(err)
    }
    p, err := spdy.NewSpdyStreamProvider(c, true)
    if err != nil {
        log.Fatal(err)
    }

    return spdy.NewTransport(p)
}

但是我得到一个错误:

cannot use spdy.NewTransport(p) (type libchan.Transport) as type InboundTransport in return argument:
    libchan.Transport does not implement InboundTransport (wrong type for WaitReceiveChannel method)
        have WaitReceiveChannel() (libchan.Receiver, error)
        want WaitReceiveChannel() (ReceiverStream, error)

我假设这个错误的意思是 ReceiverStream 的类型与 libchan.Receiver 不匹配,但我认为 golang 接口(interface)是隐式的,这意味着只要由于返回类型实现了与预期接口(interface)相同的方法,因此它将通过编译。有什么我可以更改的,以便我可以将自定义接口(interface)叠加到第三方库返回的接口(interface)上吗?

TLDR:第三方库正在返回接口(interface) Transport 的对象。 Transport 接口(interface)指定了一个方法 WaitReceiveChannel()。我有一个自定义接口(interface) InboundTransport,它还指定了 WaitReceiveChannel()。我正在调用的第三方方法返回一个对象,该对象通过方法 WaitReceiveChannel() 实现了 Transport。我假设它也会实现 InboundTransport,因为后者还指定了相同类型的 WaitReceiveChannel()。这是行不通的。为什么不呢?

最佳答案

如您所知,Go 中的接口(interface)是隐式满足的。

但是,正如错误所述,

WaitReceiveChannel() (libchan.Receiver, error)

WaitReceiveChannel() (ReceiverStream, error)

是两种不同的方法类型,导致libchan.Transport 未隐式实现InboundTransport

要解决此问题,您必须围绕 libchan.Transport 编写一个薄包装器,以正确实现 InboundTransport

type TransportWrapper struct {
    t *libchan.Transport
}

func (w *TransportWrapper) WaitReceiveChannel() (Receiver, error) {
    return w.t.WaitReceiveChannel()
}

// ...

func (ln SpdyListener) Accept(addr string) InboundTransport {
    var listener net.Listener
    var err error
    listener, err = net.Listen("tcp", addr)
    if err != nil {
        log.Fatal(err)
    }
    c, err := listener.Accept()
    if err != nil {
        log.Fatal(err)
    }
    p, err := spdy.NewSpdyStreamProvider(c, true)
    if err != nil {
        log.Fatal(err)
    }

    return &TransportWrapper{spdy.NewTransport(p)}
}

关于go - 尝试使用 go 接口(interface)实现多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51008324/

相关文章:

go - 将 JSON 整数解码为空接口(interface)会导致错误的类型断言

json - 将 interface{} 直接转换为 Golang 中的 int,其中 interface 将数字存储为字符串

go - Spdy 流接收器正在接收 nil 对象

go - 需要帮助了解 libchan 的工作原理

ruby-on-rails - 我可以从不同的服务器进程编写和利用 memcached 吗?

go - []interface{}{}中的双花括号是什么意思

Golang 类型断言/转换为中间结构

go - 如何使用其他结构变量访问不同的结构变量?

html - 通过 Golang 提供 HTML5 应用程序