尝试使用go接口实现多态 [英] trying to implement polymorphism with go interfaces
问题描述
我正在尝试在第三方库的顶部创建一个层,在这种情况下,是 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.Transport
和InboundTransport
共享一个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屋!