0

サードパーティのライブラリ (この場合はlibchan ) の上にレイヤーを作成しようとしています。私が定義したインターフェースは次のとおりです。

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

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

InboundTransportは 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定義です (これは 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 ライブラリによって返されます。

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

libchan.TransportメソッドをInboundTransport共有しているので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 インターフェイスは暗黙的であり、戻り値の型が期待されるインターフェイスと同じメソッドを実装している限り、コンパイルに合格すると思いました。サード パーツ ライブラリによって返されたインターフェイスに自己定義インターフェイスを重ね合わせることができるように、変更できるものはありますか?

TLDR: サードパーティの lib が interface のオブジェクトを返していますTransportTransportインターフェイスはメソッドを指定しますWaitReceiveChannel()InboundTransportも指定する自己定義のインターフェースがありますWaitReceiveChannel()。私が呼び出しているサードパーティのメソッドはTransport、 method を介して実装するオブジェクトを返しますWaitReceiveChannel()InboundTransport後者もWaitReceiveChannel()同じ型の a を指定しているので、それも実装すると思いました。これは機能していません。なぜだめですか?

4

1 に答える 1

4

ご存知のように、Go のインターフェイスは暗黙的に満たされます。

しかし、エラーが示すように、

WaitReceiveChannel() (libchan.Receiver, error)

WaitReceiveChannel() (ReceiverStream, error)

は 2 つの異なるメソッド タイプであるため、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)}
}
于 2018-06-24T09:23:34.793 に答える