尝试使用go接口实现多态 [英] trying to implement polymorphism with go interfaces

查看:162
本文介绍了尝试使用go接口实现多态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在第三方库的顶部创建一个层,在这种情况下,是 libchan .这是我定义的接口:

I'm trying to create a layer on top of a third party library, in this case libchan. Here's an interface I've defined:

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

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

InboundTransport旨在作为类型Transport的替代者:

The InboundTransport is meant to be a stand-in for a type Transport:

// 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匹配:

Just for context, this is the libchan.Receiver definition (please note that it matches my 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库:

The Transport is returned by the libchan library here:

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

由于libchan.TransportInboundTransport共享一个WaitReceiveChannel() (ReceiverStream, error)方法,因此我认为我应该可以将另一个替换为一个子对象,如下所示:

Since libchan.Transport and InboundTransport share a WaitReceiveChannel() (ReceiverStream, error) method, I figured I should be able to sub one for the other, like so:

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接口是隐式的,这意味着只要返回类型实现与预期接口相同的方法,它将通过编译.有什么我可以更改的东西,以便可以将自定义接口叠加到第三方库返回的接口上?

I assume that what this error means is that a type of ReceiverStream does not match libchan.Receiver, but I thought that golang interfaces were implicit, meaning that as long as the return type implements the same methods as the expected interface, it would pass compilation. Is there anything I can change so that I can superimpose a self-defined interface onto one returned by a third part library?

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

TLDR: A third party lib is returning an object of interface Transport. The Transport interface specifies a method WaitReceiveChannel(). I have a self-defined interface InboundTransport that also specifies WaitReceiveChannel(). The third-party method I'm calling returns an object that implements Transport by way of method WaitReceiveChannel(). I assumed that it would also implement InboundTransport since the latter also specifies a WaitReceiveChannel() of the same type. This isn't working. Why not?

推荐答案

您已经知道Go中的接口是隐式满足的.

As you already know interfaces in Go are satisfied implicitly.

但是,如错误所示,

WaitReceiveChannel() (libchan.Receiver, error)

WaitReceiveChannel() (ReceiverStream, error)

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

are two different method types, resulting in libchan.Transport not implicitly implementing InboundTransport.

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

To work around this you have to write a thin wrapper around libchan.Transport that implements the InboundTransport properly.

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接口实现多态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆