Golang嵌入了一个带有其他隐藏方法的接口?

时间:2015-12-22 05:08:57

标签: http go interface

我想在结构中嵌入http.ResponseWriter。没关系,它确保我的结构也实现http.ResponseWriter

type MyWriter struct {
    BytesWritten int
    http.ResponseWriter
}

但是,它不再实现http.Hijackerhttp.CloseNotifierhttp.Flusher,即使嵌入式http.ResponseWriter通常也是如此。

有没有办法做到这一点?

2 个答案:

答案 0 :(得分:2)

如果您知道响应编写器满足问题中列出的所有接口,那么您可以这样做:

type allResponseWriterInterfaces {
    http.ResponseWriter
    http.Hijacker
    http.CloseNotifier
    http.Flusher
}

type MyWriter struct {
    BytesWritten int
    allResponseWriterInterfaces
}

...

aw, ok := w.(allResponseWriterInterfaces)
if !ok {
    // oops, response writer does not implement the interfaces
    // handle the error
}
mw := MyWriter{0, aw}

如果响应编写器不满足所有接口,那就太麻烦了。有关处理响应编写器满足的情况(http.ResponseWriter,http.CloseNotifier)或(http.ResponseWriter,http.CloseNotifier,http.Hijacker)的示例,请参阅the Gorilla logger

答案 1 :(得分:0)

一种解决方案是蛮力解决方案。实际上实现所有排列。我试过这个,发现它有多痛苦。有18个排列!

所以这是一个通用的包装器。优点是您可以根据需要多次重复使用此包装。

关键是要定义一个如下界面:

// ResponseWriterTo can proxy requests to an underlying http.ResponseWriter.
// It is used with CustomResponseWriter to wrap an http.ResponseWriter with
// custom behavior.
type ResponseWriterTo interface {
    HeaderTo(w http.ResponseWriter) http.Header
    WriteHeaderTo(w http.ResponseWriter, s int)
    WriteTo(w http.ResponseWriter, b []byte) (n int, err error)

    // Additional methods that http.ResponseWriter sometimes implements.
    CloseNotifyTo(w http.CloseNotifier) <-chan bool
    FlushTo(w http.Flusher)
    HijackTo(w http.Hijacker) (net.Conn, *bufio.ReadWriter, error)

    // ReaderFrom is used by the http package to optimize reads from TCP
    // connections or from files.
    ReadFromTo(w io.ReaderFrom, r io.Reader) (n int64, err error)
}

这样我们就可以定义一个自定义的包装器函数(这是一个冗长的部分):

// CustomResponseWriter creates a http.ResponseWriter that implements as many
// hidden interfaces from the base http.ResponseWriter as are available.
func CustomResponseWriter(base http.ResponseWriter, custom ResponseWriterTo) http.ResponseWriter {
    rw := &customResponseWriter{base: base, custom: custom}

    // the base http.ResponseWriter can implement many hidden interfaces,
    // so check all permutations

    type HCFR interface {
        http.ResponseWriter
        http.Hijacker
        http.CloseNotifier
        http.Flusher
        io.ReaderFrom
    }
    if _, ok := base.(HCFR); ok {
        return struct {
            HCFR
        }{rw}
    }

    type HCF interface {
        http.ResponseWriter
        http.Hijacker
        http.CloseNotifier
        http.Flusher
    }
    if _, ok := base.(HCF); ok {
        return struct {
            HCF
        }{rw}
    }

    type HCR interface {
        http.ResponseWriter
        http.Hijacker
        http.CloseNotifier
        io.ReaderFrom
    }
    if _, ok := base.(HCR); ok {
        return struct {
            HCR
        }{rw}
    }

    type HFR interface {
        http.ResponseWriter
        http.Hijacker
        http.Flusher
        io.ReaderFrom
    }
    if _, ok := base.(HFR); ok {
        return struct {
            HFR
        }{rw}
    }

    type CFR interface {
        http.ResponseWriter
        http.CloseNotifier
        http.Flusher
        io.ReaderFrom
    }
    if _, ok := base.(CFR); ok {
        return struct {
            CFR
        }{rw}
    }

    type HC interface {
        http.ResponseWriter
        http.Hijacker
        http.CloseNotifier
    }
    if _, ok := base.(HC); ok {
        return struct {
            HC
        }{rw}
    }

    type HF interface {
        http.ResponseWriter
        http.Hijacker
        http.Flusher
    }
    if _, ok := base.(HF); ok {
        return struct {
            HF
        }{rw}
    }

    type CF interface {
        http.ResponseWriter
        http.CloseNotifier
        http.Flusher
    }
    if _, ok := base.(CF); ok {
        return struct {
            CF
        }{rw}
    }

    type HR interface {
        http.ResponseWriter
        http.Hijacker
        io.ReaderFrom
    }
    if _, ok := base.(HR); ok {
        return struct {
            HR
        }{rw}
    }

    type CR interface {
        http.ResponseWriter
        http.CloseNotifier
        io.ReaderFrom
    }
    if _, ok := base.(CR); ok {
        return struct {
            CR
        }{rw}
    }

    type FR interface {
        http.ResponseWriter
        http.Flusher
        io.ReaderFrom
    }
    if _, ok := base.(FR); ok {
        return struct {
            FR
        }{rw}
    }

    type H interface {
        http.ResponseWriter
        http.Hijacker
    }
    if _, ok := base.(H); ok {
        return struct {
            H
        }{rw}
    }

    type C interface {
        http.ResponseWriter
        http.CloseNotifier
    }
    if _, ok := base.(C); ok {
        return struct {
            C
        }{rw}
    }

    type F interface {
        http.ResponseWriter
        http.Flusher
    }
    if _, ok := base.(F); ok {
        return struct {
            F
        }{rw}
    }

    type R interface {
        http.ResponseWriter
        io.ReaderFrom
    }
    if _, ok := base.(R); ok {
        return struct {
            R
        }{rw}
    }

    return struct {
        http.ResponseWriter
    }{rw}
}

// customResponseWriter allows us to adapt a ResponseWriterTo to a ResponseWriter.
type customResponseWriter struct {
    base   http.ResponseWriter
    custom ResponseWriterTo
}

func (w *customResponseWriter) Header() http.Header         { return w.custom.HeaderTo(w.base) }
func (w *customResponseWriter) Write(b []byte) (int, error) { return w.custom.WriteTo(w.base, b) }
func (w *customResponseWriter) WriteHeader(s int)           { w.custom.WriteHeaderTo(w.base, s) }
func (w *customResponseWriter) CloseNotify() <-chan bool {
    return w.custom.CloseNotifyTo(w.base.(http.CloseNotifier))
}
func (w *customResponseWriter) Flush() { w.custom.FlushTo(w.base.(http.Flusher)) }
func (w *customResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
    return w.custom.HijackTo(w.base.(http.Hijacker))
}
func (w *customResponseWriter) ReadFrom(r io.Reader) (n int64, err error) {
    return w.custom.ReadFromTo(w.base.(io.ReaderFrom), r)
}

我们的想法是将正确的接口嵌入到结构中。那么只有&#34;对&#34;方法暴露。